Venha aprender a criar um dos jogos clássicos do início da era dos celulares, agora em formato DIY com seu Arduino, semelhante ao famoso Jogo da Cobrinha!
Sendo um jogo simples, que pode ser feito com poucos componentes e ainda assim garantir bastante diversão até os dias de hoje, um jogo atemporal.
Este pequeno projeto pode ser o pontapé inicial para você deslumbrar do muito Maker e finalmente realizar seus próprios projetos, basta ter criatividade, alguns componentes e mão na massa!
Material Necessário
- 1x Arduino UNO R3 + Cabo USB AB;
- 1x Protoboard;
- 1x Matriz de LED 8×8;
- 1x Kit Push Button 12×12 Colorido / Chave táctil 12×12;
- 1x Jumper Macho-Macho;
- 1x Jumper Macho-Fêmea;
- 1x Jumper Rígidos (Opcional, para acabamento).
Diagrama de Conexão
Programação Jogo da cobrinha DIY:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 |
// The MAX7219 uses SPI communication protocol...Hence, import SPI.h library #include <SPI.h> // The chip select pin #define CS 10 // Few necessary registers for configuring the MAX7219 chip #define DECODE_MODE 9 #define INTENSITY 0x0A #define SCAN_LIMIT 0x0B #define SHUTDOWN 0x0C #define DISPLAY_TEST 0x0F // Buttons used for controlling the snake #define left_button 2 #define right_button 3 volatile byte move_left = 0; volatile byte move_right = 0; // Varibles for snake int snake_l = 2; const int max_len = 30; int snake[max_len][2]; byte cur_heading = 0; // Variable for food blob int blob[2] = { 0, 0 }; int is_eaten = 1; // The game scene byte scene[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // A general function to send data to the MAX7219 void SendData(uint8_t address, uint8_t value) { digitalWrite(CS, LOW); SPI.transfer(address); // Send address. SPI.transfer(value); // Send the value. digitalWrite(CS, HIGH); // Finish transfer. } // Function to initialize the game variables void init_game() { is_eaten = 1; move_left = 0; move_right = 0; cur_heading = 0; snake_l = 2; for (int i = 0; i < max_len; i++) for (int j = 0; j < 2; j++) snake[i][j] = 0; snake[max_len - 1][0] = 2; snake[max_len - 1][1] = 5; snake[max_len - 2][0] = 1; snake[max_len - 2][1] = 5; refresh_scene(); while ((move_left || move_right) == 0) ; move_left = 0; move_right = 0; } // Function to draw snake on gamescene void spawn_snake() { // If the snake goes out of the scene, it enters from the other side for (int j = max_len - snake_l; j < max_len; j++) { if (snake[j][0] <= 0) snake[j][0] = 8 + snake[j][0]; else if (snake[j][0] >= 9) snake[j][0] = snake[j][0] - 8; if (snake[j][1] <= 0) snake[j][1] = 8 + snake[j][1]; else if (snake[j][1] >= 9) snake[j][1] = snake[j][1] - 8; // Draw the snake on the LED matrix scene[snake[j][0] - 1] |= (1 << (snake[j][1] - 1)); } } // Function to update the position and length of the snake void snake_move() { // If snake eats a blob...Increase length if (snake[max_len - 1][0] == blob[0] && snake[max_len - 1][1] == blob[1]) { is_eaten = 1; snake_l += 1; } // Move each pixel forward for (int i = snake_l - 1; i >= 1; i--) { snake[max_len - 1 - i][0] = snake[max_len - i][0]; snake[max_len - 1 - i][1] = snake[max_len - i][1]; } // Move the head according to button input if (move_left == 1) { if (cur_heading == 0) { cur_heading = 1; snake[max_len - 1][1] -= 1; } else if (cur_heading == 1) { cur_heading = 2; snake[max_len - 1][0] -= 1; } else if (cur_heading == 2) { cur_heading = 3; snake[max_len - 1][1] += 1; } else if (cur_heading == 3) { cur_heading = 0; snake[max_len - 1][0] += 1; } move_left = 0; } else if (move_right == 1) { if (cur_heading == 0) { cur_heading = 3; snake[max_len - 1][1] += 1; } else if (cur_heading == 1) { cur_heading = 0; snake[max_len - 1][0] += 1; } else if (cur_heading == 2) { cur_heading = 1; snake[max_len - 1][1] -= 1; } else if (cur_heading == 3) { cur_heading = 2; snake[max_len - 1][0] -= 1; } move_right = 0; } else { if (cur_heading == 0) { snake[max_len - 1][0] += 1; } else if (cur_heading == 1) { snake[max_len - 1][1] -= 1; } else if (cur_heading == 2) { snake[max_len - 1][0] -= 1; } else if (cur_heading == 3) { snake[max_len - 1][1] += 1; } } } // Function to generate a blob and draw the blob on the gamescene void blob_generator() { // If blob is eaten by the snake, generate one if (is_eaten) { blob[0] = random(1, 9); blob[1] = random(1, 9); } // Draw the blob on the gamescene scene[blob[0] - 1] |= (1 << (blob[1] - 1)); is_eaten = 0; } // Function to redraw the gamescene to the LED matrix with updated variables void refresh_scene() { for (int i = 0; i < 8; i++) scene[i] = 0x00; snake_move(); spawn_snake(); blob_generator(); for (int i = 1; i < 9; i++) SendData(i, scene[i - 1]); } // Callback for interrupt attached to left button void update_left() { move_left = 1; } // Callback for interrupt attached to right button void update_right() { move_right = 1; } // Setup function void setup() { // GPIO Configuration pinMode(left_button, INPUT_PULLUP); pinMode(right_button, INPUT_PULLUP); pinMode(CS, OUTPUT); // SPI configuration SPI.setBitOrder(MSBFIRST); // Most significant bit first SPI.begin(); // Start SPI SendData(DISPLAY_TEST, 0x00); // Finish test mode. SendData(DECODE_MODE, 0x00); // Disable BCD mode. SendData(INTENSITY, 0x0F); // Use MAX intensity. (F = 15) SendData(SCAN_LIMIT, 0x0f); // Scan all digits. SendData(SHUTDOWN, 0x01); // Turn on chip. // Random seed generation...Uses the noise in the analog channel 0 to create a random seed randomSeed(analogRead(0)); // Attach interrupts to the buttons attachInterrupt(digitalPinToInterrupt(left_button), update_left, FALLING); attachInterrupt(digitalPinToInterrupt(right_button), update_right, FALLING); // Enable interrupt sei(); // Start the game init_game(); } void loop() { // Check if snake is at max length if (snake_l == max_len) { // If yes, display win and restart byte win_scene[8] = { B11100011, B00100100, B01000010, B11100100, B00000011, 0, B00011100, 0 }; for (int i = 1; i < 9; i++) SendData(i, win_scene[i - 1]); delay(5000); init_game(); } // Check if snake has collided with itself for (int i = 0; i < max_len - 1; i++) { if (snake[i][0] == snake[max_len - 1][0] && snake[i][1] == snake[max_len - 1][1]) { // If yes, blink all leds and restart the game delay(1000); for (int j = 0; j < 4; j++) { SendData(DISPLAY_TEST, 0x01); delay(500); SendData(DISPLAY_TEST, 0x00); delay(500); } init_game(); break; } } // Keep refreshing the matrix with updated data.... refresh_scene(); // ...Every 0.5 secs delay(250); } |
Resultado do projeto
Acompanhe nossos vídeos nas redes sociais @usinainfo.
Ver essa foto no Instagram
Funcionamento do jogo da cobrinha
Seu funcionamento é bastante simples, utilizamos os botões que estão utilizando pull-up por meio do código do Arduino, assim ativando seus resistores internos. Conforme eles serem pressionados deixam em LOW sua entrada, detectando o clique.
A Matriz de LED 8×8 irá mostrar a cobrinha e as “comidas” para crescer, atualmente conta com sistema de perder ao colidir com seu próprio corpo e ganhar ao pegar 15 comidas.
Este jogo é bastante customizável, sendo possível alterar no código na variável “max_len” para poder crescer mais ainda a cobrinha. Contudo também é possível alterar a velocidade do jogo, no delay ao final do void loop.
E se você for sagaz, irá conseguir alterar a tela de vitória em “win_scene”, contudo, fica o desafio para você maker.