Use the code below to bring your Snake game to life. This code initializes the LED matrix, defines snake movement, and handles button inputs for game control.
/*
* Snake Game Example for Nova Board
*
* Button Connections:
* - UP Button: connected to pin 2
* - LEFT Button: connected to pin 3
* - DOWN Button: connected to pin 4
* - RIGHT Button: connected to pin 5
* - RESET Button: connected to pin 6
*
* Note: External pull-down resistors are used with the buttons to ensure stable readings.
*
* License:
* This project is open-source hardware and software, released under the MIT License.
* See the LICENSE file for details.
*/
#include <FastLED.h>
// LED matrix settings
#define NUM_LEDS 70 // Total number of LEDs in the matrix
#define DATA_PIN 22 // Data pin for controlling the LEDs
#define BRIGHTNESS 10 // LED brightness level (0-255)
CRGB leds[NUM_LEDS]; // Array to hold LED color values
// Button pins
#define UP_BUTTON 2 // Pin for UP button
#define LEFT_BUTTON 3 // Pin for LEFT button
#define DOWN_BUTTON 4 // Pin for DOWN button
#define RIGHT_BUTTON 5 // Pin for RIGHT button
#define RESET_BUTTON 6 // Pin for RESET button
// Matrix Layout - Maps 10x7 grid to LED indices
int matrix[10][7] = {
{69, 50, 49, 30, 29, 10, 9},
{68, 51, 48, 31, 28, 11, 8},
{67, 52, 47, 32, 27, 12, 7},
{66, 53, 46, 33, 26, 13, 6},
{65, 54, 45, 34, 25, 14, 5},
{64, 55, 44, 35, 24, 15, 4},
{63, 56, 43, 36, 23, 16, 3},
{62, 57, 42, 37, 22, 17, 2},
{61, 58, 41, 38, 21, 18, 1},
{60, 59, 40, 39, 20, 19, 0}
};
// Snake properties
struct Point { int x, y; }; // Structure to define a point (x, y) on the matrix
Point snake[100]; // Array to hold snake body segments
int snakeLength; // Length of the snake
int dx, dy; // Direction variables (dx, dy)
Point food; // Position of food on the matrix
bool gameOver; // Flag to check if the game is over
// Speed settings
unsigned long snakeSpeed = 400; // Speed of the snake, adjust this to change game speed
unsigned long lastMoveTime = 0; // Time when the snake last moved
// Setup function - Initializes the game and LEDs
void setup() {
FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS); // Initialize FastLED
FastLED.setBrightness(BRIGHTNESS); // Set LED brightness
randomSeed(analogRead(0)); // Seed random generator for food placement
initializeGame(); // Start the game
}
// Main game loop
void loop() {
if (gameOver) { // If game is over, wait for RESET button
if (digitalRead(RESET_BUTTON) == HIGH) {
initializeGame(); // Restart game when RESET button is pressed
}
return;
}
// Update snake direction based on button input
if (digitalRead(UP_BUTTON) == HIGH && dy == 0) { dx = 0; dy = -1; }
if (digitalRead(LEFT_BUTTON) == HIGH && dx == 0) { dx = -1; dy = 0; }
if (digitalRead(DOWN_BUTTON) == HIGH && dy == 0) { dx = 0; dy = 1; }
if (digitalRead(RIGHT_BUTTON) == HIGH && dx == 0) { dx = 1; dy = 0; }
// Move snake based on game speed
unsigned long currentMillis = millis();
if (currentMillis - lastMoveTime >= snakeSpeed) { // Check if enough time has passed
moveSnake(); // Move the snake to the next position
lastMoveTime = currentMillis; // Update move time
// Update LED display
FastLED.clear(); // Clear the previous LED states
// Set snake head color to green
leds[matrix[snake[0].y][snake[0].x]] = CRGB::Green;
// Set snake body color to green
for (int i = 1; i < snakeLength; i++) {
leds[matrix[snake[i].y][snake[i].x]] = CRGB::Green;
}
// Set food color to red
leds[matrix[food.y][food.x]] = CRGB::Red;
FastLED.show(); // Display updated LEDs
}
}
// Initialize or reset game properties
void initializeGame() {
snakeLength = 3; // Start with a small snake
snake[0] = {3, 5}; // Initial snake head position
snake[1] = {3, 6}; // Initial snake body
snake[2] = {4, 6}; // Initial snake tail
dx = 0; // Initial direction: not moving horizontally
dy = -1; // Initial direction: moving up
gameOver = false; // Game starts with game over set to false
spawnFood(); // Spawn the first food
}
// Move snake and handle collisions
void moveSnake() {
// Calculate new head position based on direction
Point newHead = { snake[0].x + dx, snake[0].y + dy };
// Check for collision with walls
if (newHead.x < 0 || newHead.x >= 7 || newHead.y < 0 || newHead.y >= 10) {
gameOver = true; // Set game over if snake hits wall
return;
}
// Check for collision with itself
for (int i = 0; i < snakeLength; i++) {
if (snake[i].x == newHead.x && snake[i].y == newHead.y) {
gameOver = true; // Set game over if snake hits itself
return;
}
}
// Move the snake by shifting body segments
for (int i = snakeLength; i > 0; i--) {
snake[i] = snake[i - 1];
}
snake[0] = newHead; // Update the new head position
// Check if snake ate the food
if (newHead.x == food.x && newHead.y == food.y) {
snakeLength++; // Increase snake length
spawnFood(); // Spawn new food
}
}
// Spawn food at a random position
void spawnFood() {
while (true) {
food.x = random(7); // Random x-coordinate within the matrix
food.y = random(10); // Random y-coordinate within the matrix
bool onSnake = false;
// Check if food position is on the snake
for (int i = 0; i < snakeLength; i++) {
if (snake[i].x == food.x && snake[i].y == food.y) {
onSnake = true; // If it is, set flag to true and retry
break;
}
}
// Exit loop if food is not on the snake
if (!onSnake) break;
}
}