Welcome to Hackster!
Hackster is a community dedicated to learning hardware, from beginner to pro. Join us, it's free!
Arnov Sharma
Published © MIT

Snake Game Console

A handheld game console based around the Raspberry Pi PICO 2 combined with the Waveshare RGB-Matrix-P3.

IntermediateFull instructions provided735

Things used in this project

Hardware components

Raspberry Pi Pico 2
Raspberry Pi Pico 2
×1
PCBWay Custom PCB
PCBWay Custom PCB
×1

Software apps and online services

Fusion
Autodesk Fusion
Arduino IDE
Arduino IDE

Hand tools and fabrication machines

3D Printer (generic)
3D Printer (generic)

Story

Read more

Custom parts and enclosures

STEP FILE

Fusion360File

Schematics

SCH

Code

code

C/C++
#include <Adafruit_Protomatter.h>

// Pin definitions
#define R1 2
#define G1 3
#define B1 4
#define R2 5
#define G2 8
#define B2 9
#define A 10
#define B 16
#define C 18
#define D 20
#define CLK 11
#define LAT 12
#define OE 13

// Button pins
#define BUTTON_UP 7
#define BUTTON_DOWN 6
#define BUTTON_LEFT 15
#define BUTTON_RIGHT 14

#define WIDTH 64
#define HEIGHT 32
#define SNAKE_LENGTH 8

uint8_t rgbPins[] = { R1, G1, B1, R2, G2, B2 };
uint8_t addrPins[] = { A, B, C, D };

Adafruit_Protomatter matrix(WIDTH, HEIGHT, 1, rgbPins, 4, addrPins, CLK, LAT, OE, false);

struct SnakeSegment {
  int x;
  int y;
};

SnakeSegment snake[WIDTH * HEIGHT]; // Increased size to allow snake growth
int snakeLength = SNAKE_LENGTH;
int dx = 1, dy = 0;
uint16_t snakeColor = matrix.color565(0, 255, 0); // Green color
uint16_t foodColor = matrix.color565(255, 0, 0); // Red color
uint16_t gameOverColor = matrix.color565(255, 0, 0); // Red color for "Game Over" screen
int foodX, foodY;
int score = 0; // Score variable
bool gameOver = false; // Game over flag

void placeFood() {
  // Ensure the new food position does not overlap with the snake
  bool foodOnSnake;
  do {
    foodX = random(WIDTH);
    foodY = random(HEIGHT);
    foodOnSnake = false;
    for (int i = 0; i < snakeLength; i++) {
      if (snake[i].x == foodX && snake[i].y == foodY) {
        foodOnSnake = true;
        break;
      }
    }
  } while (foodOnSnake);
}

void setup() {
  matrix.begin();
  pinMode(BUTTON_UP, INPUT_PULLUP);
  pinMode(BUTTON_DOWN, INPUT_PULLUP);
  pinMode(BUTTON_LEFT, INPUT_PULLUP);
  pinMode(BUTTON_RIGHT, INPUT_PULLUP);

  // Initialize snake in the middle of the screen
  for (int i = 0; i < snakeLength; i++) {
    snake[i] = { WIDTH / 2 - i, HEIGHT / 2 };
  }

  placeFood(); // Place initial food

  // Clear screen
  matrix.fillScreen(matrix.color565(0, 0, 0));
  matrix.show();
}

void drawScore() {
  matrix.setCursor(WIDTH - 10, 2); // Adjust cursor to top-right corner
  matrix.setTextColor(matrix.color565(255, 255, 255)); // Set text color to white for visibility
  matrix.print(score); // Display only the score number
}

void checkGameOver() {
  // Check if snake collides with itself
  for (int i = 1; i < snakeLength; i++) {
    if (snake[0].x == snake[i].x && snake[0].y == snake[i].y) {
      gameOver = true;
      break;
    }
  }
}

void resetGame() {
  snakeLength = SNAKE_LENGTH;
  dx = 1;
  dy = 0;
  score = 0;
  gameOver = false;

  // Initialize snake in the middle of the screen
  for (int i = 0; i < snakeLength; i++) {
    snake[i] = { WIDTH / 2 - i, HEIGHT / 2 };
  }

  placeFood(); // Place initial food
}

void drawGameOver() {
  // Fill the screen with red
  matrix.fillScreen(gameOverColor);

  // Draw "Game Over!" in black
  uint16_t blackColor = matrix.color565(0, 0, 0);
  matrix.setCursor((WIDTH / 2) - 30, (HEIGHT / 2) - 4);
  matrix.setTextColor(blackColor);
  matrix.print("Game Over!");

  // Display score in white
  matrix.setCursor(WIDTH - 10, 2); // Adjust cursor to top-right corner
  matrix.setTextColor(blackColor);
  matrix.print(score);
}

void loop() {
  if (gameOver) {
    drawGameOver();
    matrix.show();
    delay(5000); // Wait 5 seconds
    resetGame(); // Reset the game
    return;
  }

  // Check button states and update direction
  if (!digitalRead(BUTTON_UP) && dy == 0) {
    dx = 0; dy = -1;
  } else if (!digitalRead(BUTTON_DOWN) && dy == 0) {
    dx = 0; dy = 1;
  } else if (!digitalRead(BUTTON_LEFT) && dx == 0) {
    dx = -1; dy = 0;
  } else if (!digitalRead(BUTTON_RIGHT) && dx == 0) {
    dx = 1; dy = 0;
  }

  // Move snake
  for (int i = snakeLength - 1; i > 0; i--) {
    snake[i] = snake[i - 1];
  }
  snake[0].x += dx;
  snake[0].y += dy;

  // Wrap around screen edges
  if (snake[0].x >= WIDTH) snake[0].x = 0;
  if (snake[0].x < 0) snake[0].x = WIDTH - 1;
  if (snake[0].y >= HEIGHT) snake[0].y = 0;
  if (snake[0].y < 0) snake[0].y = HEIGHT - 1;

  // Check if snake eats the food
  if (snake[0].x == foodX && snake[0].y == foodY) {
    snakeLength++;
    score++; // Increment score
    placeFood();
  }

  // Clear screen
  matrix.fillScreen(matrix.color565(0, 0, 0));

  // Draw snake
  for (int i = 0; i < snakeLength; i++) {
    matrix.drawPixel(snake[i].x, snake[i].y, snakeColor);
  }

  // Draw food
  matrix.drawPixel(foodX, foodY, foodColor);

  // Draw score
  drawScore();

  // Update display
  matrix.show();

  // Check for game over
  checkGameOver();

  delay(100); // Adjust delay for speed control
}

Credits

Arnov Sharma
339 projects • 344 followers
Just your average MAKER
Contact

Comments

Please log in or sign up to comment.