Arnov Sharma
Published © MIT

Snake Game Console MAX

An enlarged and updated version of the previously created Snake Game Console project

BeginnerFull instructions provided1 hour448
Snake Game Console MAX

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

cad file

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 6
#define BUTTON_DOWN 7
#define BUTTON_LEFT 14
#define BUTTON_RIGHT 15

// Panel settings
#define PANEL_WIDTH 64
#define PANEL_HEIGHT 32
#define NUM_PANELS 2
#define WIDTH (PANEL_WIDTH * NUM_PANELS)
#define HEIGHT PANEL_HEIGHT
#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];
int snakeLength = SNAKE_LENGTH;
int dx = 1, dy = 0;
uint16_t snakeColor = matrix.color565(0, 255, 0);
uint16_t foodColor = matrix.color565(255, 0, 0);
uint16_t borderColor = matrix.color565(255, 255, 255);
uint16_t gameOverColor = matrix.color565(255, 0, 0);
int foodX, foodY;
int score = 0;
bool gameOver = false;

// Speed control variables
#define BASE_DELAY 100  // Normal speed
#define FAST_DELAY 50   // Faster speed when button is held

void placeFood() {
  bool foodOnSnake;
  do {
    foodX = random(1, WIDTH - 1);  // Ensure food doesn't spawn on the border
    foodY = random(1, HEIGHT - 1);
    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);

  for (int i = 0; i < snakeLength; i++) {
    snake[i] = { WIDTH / 2 - i, HEIGHT / 2 };
  }

  placeFood();
  matrix.fillScreen(0);
  matrix.show();
}

void drawScore() {
  matrix.setCursor(WIDTH - 20, 2);
  matrix.setTextColor(matrix.color565(255, 255, 255));
  matrix.print(score);
}

void drawBorder() {
  for (int x = 0; x < WIDTH; x++) {
    matrix.drawPixel(x, 0, borderColor);            // Top border
    matrix.drawPixel(x, HEIGHT - 1, borderColor);   // Bottom border
  }
  for (int y = 0; y < HEIGHT; y++) {
    matrix.drawPixel(0, y, borderColor);            // Left border
    matrix.drawPixel(WIDTH - 1, y, borderColor);    // Right border
  }
}

void checkGameOver() {
  if (snake[0].x <= 0 || snake[0].x >= WIDTH - 1 || 
      snake[0].y <= 0 || snake[0].y >= HEIGHT - 1) {  
    gameOver = true;  // Snake hits the border
  }
  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;

  for (int i = 0; i < snakeLength; i++) {
    snake[i] = { WIDTH / 2 - i, HEIGHT / 2 };
  }
  placeFood();
}

void drawGameOver() {
  matrix.fillScreen(gameOverColor);
  uint16_t black = matrix.color565(0, 0, 0);
  matrix.setCursor((WIDTH / 2) - 30, (HEIGHT / 2) - 4);
  matrix.setTextColor(black);
  matrix.print("Game Over!");
  matrix.setCursor(WIDTH - 20, 2);
  matrix.print(score);
}

void loop() {
  if (gameOver) {
    drawGameOver();
    matrix.show();
    delay(5000);
    resetGame();
    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; }

  // Determine delay based on button press
  int currentDelay = BASE_DELAY;
  if (!digitalRead(BUTTON_UP) || !digitalRead(BUTTON_DOWN) || 
      !digitalRead(BUTTON_LEFT) || !digitalRead(BUTTON_RIGHT)) {
    currentDelay = FAST_DELAY;  // Reduce delay when holding a button
  }

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

  if (snake[0].x == foodX && snake[0].y == foodY) {
    snakeLength++;
    score++;
    placeFood();
  }

  matrix.fillScreen(0);
  drawBorder();  // Draw border each frame

  for (int i = 0; i < snakeLength; i++) {
    matrix.drawPixel(snake[i].x, snake[i].y, snakeColor);
  }
  matrix.drawPixel(foodX, foodY, foodColor);
  drawScore();
  matrix.show();

  checkGameOver();
  delay(currentDelay);  // Adjust speed dynamically based on input
}

Credits

Arnov Sharma
352 projects • 360 followers
I'm Arnov. I build, design, and experiment with tech—3D printing, PCB design, and retro consoles are my jam.

Comments