Components and supplies
MAX7219 Module
Push Button
Mini breadboard - White
Arduino Nano
Apps and platforms
Arduino IDE 2.0 (beta)
Project description
Code
SnakeGame.ino
cpp
The code to run the snake game on the arduino
1// The MAX7219 uses SPI communication protocol...Hence, import SPI.h library 2#include <SPI.h> 3 4// The chip select pin 5#define CS 10 6 7// Few necessary registers for configuring the MAX7219 chip 8#define DECODE_MODE 9 9#define INTENSITY 0x0A 10#define SCAN_LIMIT 0x0B 11#define SHUTDOWN 0x0C 12#define DISPLAY_TEST 0x0F 13 14// Buttons used for controlling the snake 15#define left_button 2 16#define right_button 3 17 18volatile byte move_left = 0; 19volatile byte move_right = 0; 20 21// Varibles for snake 22int snake_l = 2; 23const int max_len = 15; 24int snake[max_len][2]; 25byte cur_heading = 0; 26 27// Variable for food blob 28int blob[2] = { 0, 0 }; 29int is_eaten = 1; 30 31// The game scene 32byte scene[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 33 34// A general function to send data to the MAX7219 35void SendData(uint8_t address, uint8_t value) { 36 digitalWrite(CS, LOW); 37 SPI.transfer(address); // Send address. 38 SPI.transfer(value); // Send the value. 39 digitalWrite(CS, HIGH); // Finish transfer. 40} 41 42// Function to initialize the game variables 43void init_game() { 44 is_eaten = 1; 45 move_left = 0; 46 move_right = 0; 47 cur_heading = 0; 48 snake_l = 2; 49 for (int i = 0; i < max_len; i++) 50 for (int j = 0; j < 2; j++) 51 snake[i][j] = 0; 52 snake[max_len - 1][0] = 2; 53 snake[max_len - 1][1] = 5; 54 snake[max_len - 2][0] = 1; 55 snake[max_len - 2][1] = 5; 56 refresh_scene(); 57 while ((move_left || move_right) == 0) 58 ; 59 move_left = 0; 60 move_right = 0; 61} 62 63// Function to draw snake on gamescene 64void spawn_snake() { 65 // If the snake goes out of the scene, it enters from the other side 66 for (int j = max_len - snake_l; j < max_len; j++) { 67 if (snake[j][0] <= 0) 68 snake[j][0] = 8 + snake[j][0]; 69 else if (snake[j][0] >= 9) 70 snake[j][0] = snake[j][0] - 8; 71 if (snake[j][1] <= 0) 72 snake[j][1] = 8 + snake[j][1]; 73 else if (snake[j][1] >= 9) 74 snake[j][1] = snake[j][1] - 8; 75 76 // Draw the snake on the LED matrix 77 scene[snake[j][0] - 1] |= (1 << (snake[j][1] - 1)); 78 } 79} 80 81// Function to update the position and length of the snake 82void snake_move() { 83 // If snake eats a blob...Increase length 84 if (snake[max_len - 1][0] == blob[0] && snake[max_len - 1][1] == blob[1]) { 85 is_eaten = 1; 86 snake_l += 1; 87 } 88 89 // Move each pixel forward 90 for (int i = snake_l - 1; i >= 1; i--) { 91 snake[max_len - 1 - i][0] = snake[max_len - i][0]; 92 snake[max_len - 1 - i][1] = snake[max_len - i][1]; 93 } 94 95 // Move the head according to button input 96 if (move_left == 1) { 97 if (cur_heading == 0) { 98 cur_heading = 1; 99 snake[max_len - 1][1] -= 1; 100 } else if (cur_heading == 1) { 101 cur_heading = 2; 102 snake[max_len - 1][0] -= 1; 103 } else if (cur_heading == 2) { 104 cur_heading = 3; 105 snake[max_len - 1][1] += 1; 106 } else if (cur_heading == 3) { 107 cur_heading = 0; 108 snake[max_len - 1][0] += 1; 109 } 110 move_left = 0; 111 } else if (move_right == 1) { 112 if (cur_heading == 0) { 113 cur_heading = 3; 114 snake[max_len - 1][1] += 1; 115 } else if (cur_heading == 1) { 116 cur_heading = 0; 117 snake[max_len - 1][0] += 1; 118 } else if (cur_heading == 2) { 119 cur_heading = 1; 120 snake[max_len - 1][1] -= 1; 121 } else if (cur_heading == 3) { 122 cur_heading = 2; 123 snake[max_len - 1][0] -= 1; 124 } 125 move_right = 0; 126 } else { 127 if (cur_heading == 0) { 128 snake[max_len - 1][0] += 1; 129 } else if (cur_heading == 1) { 130 snake[max_len - 1][1] -= 1; 131 } else if (cur_heading == 2) { 132 snake[max_len - 1][0] -= 1; 133 } else if (cur_heading == 3) { 134 snake[max_len - 1][1] += 1; 135 } 136 } 137} 138 139// Function to generate a blob and draw the blob on the gamescene 140void blob_generator() { 141 // If blob is eaten by the snake, generate one 142 if (is_eaten) { 143 blob[0] = random(1, 9); 144 blob[1] = random(1, 9); 145 } 146 147 // Draw the blob on the gamescene 148 scene[blob[0] - 1] |= (1 << (blob[1] - 1)); 149 is_eaten = 0; 150} 151 152// Function to redraw the gamescene to the LED matrix with updated variables 153void refresh_scene() { 154 for (int i = 0; i < 8; i++) 155 scene[i] = 0x00; 156 snake_move(); 157 spawn_snake(); 158 blob_generator(); 159 for (int i = 1; i < 9; i++) 160 SendData(i, scene[i - 1]); 161} 162 163// Callback for interrupt attached to left button 164void update_left() { 165 move_left = 1; 166} 167 168// Callback for interrupt attached to right button 169void update_right() { 170 move_right = 1; 171} 172 173// Setup function 174void setup() { 175 // GPIO Configuration 176 pinMode(left_button, INPUT_PULLUP); 177 pinMode(right_button, INPUT_PULLUP); 178 pinMode(CS, OUTPUT); 179 180 // SPI configuration 181 SPI.setBitOrder(MSBFIRST); // Most significant bit first 182 SPI.begin(); // Start SPI 183 SendData(DISPLAY_TEST, 0x00); // Finish test mode. 184 SendData(DECODE_MODE, 0x00); // Disable BCD mode. 185 SendData(INTENSITY, 0x01); // Use lowest intensity. 186 SendData(SCAN_LIMIT, 0x0f); // Scan all digits. 187 SendData(SHUTDOWN, 0x01); // Turn on chip. 188 189 // Random seed generation...Uses the noise in the analog channel 0 to create a random seed 190 randomSeed(analogRead(0)); 191 192 // Attach interrupts to the buttons 193 attachInterrupt(digitalPinToInterrupt(left_button), update_left, FALLING); 194 attachInterrupt(digitalPinToInterrupt(right_button), update_right, FALLING); 195 196 // Enable interrupt 197 sei(); 198 199 // Start the game 200 init_game(); 201} 202 203void loop() { 204 // Check if snake is at max length 205 if (snake_l == max_len) { 206 // If yes, display win and restart 207 byte win_scene[8] = { B11100011, B00100100, B01000010, B11100100, B00000011, 0, B00011100, 0 }; 208 for (int i = 1; i < 9; i++) 209 SendData(i, win_scene[i - 1]); 210 delay(5000); 211 init_game(); 212 } 213 214 // Check if snake has collided with itself 215 for (int i = 0; i < max_len - 1; i++) { 216 if (snake[i][0] == snake[max_len - 1][0] && snake[i][1] == snake[max_len - 1][1]) { 217 // If yes, blink all leds and restart the game 218 delay(1000); 219 for (int j = 0; j < 4; j++) { 220 SendData(DISPLAY_TEST, 0x01); 221 delay(500); 222 SendData(DISPLAY_TEST, 0x00); 223 delay(500); 224 } 225 init_game(); 226 break; 227 } 228 } 229 230 // Keep refreshing the matrix with updated data.... 231 refresh_scene(); 232 // ...Every 0.5 secs 233 delay(500); 234}
Downloadable files
Source Code
Code for uploading on Arduino Nano
SnakeGame.ino
Circuit Diagram
Wire up the circuit accordingly.
SnakeGame.png
PCB Design
Gerber files for printing PCB
SnakeGame_Gerber.zip
Comments
Only logged in users can leave comments
xerianio
4 months ago
The challenges and setbacks in online games teach players https://geometrygame.org/ to persevere, building resilience and a growth mindset.