Projeto Snake Game no Arduino: Um Passo Importante para o Desenvolvimento da Robótica
Projeto Snake Game no Arduino: Um Passo Importante para o Desenvolvimento da Robótica
Introdução
O jogo Snake (Cobrinha) é um clássico da programação e da eletrônica, sendo frequentemente reproduzido em microcontroladores como o Arduino. Neste artigo, exploraremos como implementar o jogo Snake utilizando uma matriz de LED 8x8, um módulo joystick e um potenciômetro para controle. Além disso, discutiremos como esse projeto simples é fundamental para o aprendizado em robótica e automação.
Materiais Necessários
Para desenvolver este projeto, você precisará dos seguintes componentes:
Arduino Uno (ou similar)
Matriz de LED 8x8 (controlada por um MAX7219)
Módulo Joystick (para controle da cobra)
Potenciômetro (para ajuste de velocidade)
Jumpers
Protoboard (opcional, para organização)
Funcionamento do Projeto
O jogo Snake consiste em controlar uma cobra que cresce conforme ela "come" pontos aleatórios na tela. O objetivo é evitar que a cobra colida com seu próprio corpo ou com as bordas do display.
1. Controle com Joystick e Potenciômetro
O joystick será usado para definir a direção da cobra (cima, baixo, esquerda, direita).
O potenciômetro ajustará a velocidade do jogo, alterando o delay entre os movimentos.
2. Exibição na Matriz de LED 8x8
A matriz de LEDs exibirá:
A cobra (sequência de LEDs acesos).
A comida (um LED piscando em uma posição aleatória).
A pontuação (pode ser exibida no Serial Monitor ou usando LEDs adicionais).
Código Básico no Arduino
Abaixo está um exemplo simplificado do código para o jogo Snake:
#include "LedControl.h" // LedControl library is used for controlling a LED matrix.
// there are defined all the pinsstruct Pin {static const short joystickX = A5; // joystick X axis pinstatic const short joystickY = A4; // joystick Y axis pinstatic const short joystickVCC = 1; // virtual VCC for the joystick (Analog 1) (to make the joystick connectable right next to the arduino nano)static const short joystickGND = 2; // virtual GND for the joystick (Analog 0) (to make the joystick connectable right next to the arduino nano)static const short potentiometer = A3; // potentiometer for snake speed controlstatic const short CLK = 8; // clock for LED matrixstatic const short CS = 9; // chip-select for LED matrixstatic const short DIN = 10; // data-in for LED matrix};// LED matrix brightness: between 0(darkest) and 15(brightest)const short intensity = 8;// lower = faster message scrollingconst short messageSpeed = 5;// initial snake length (1...63, recommended 3)const short initialSnakeLength = 3;void setup() {Serial.begin(115200); // set the same baud rate on your Serial Monitorinitialize(); // initialize pins & LED matrixcalibrateJoystick(); // calibrate the joystick home (do not touch it)showSnakeMessage(); // scrolls the 'snake' message around the matrix}void loop() {generateFood(); // if there is no food, generate onescanJoystick(); // watches joystick movements & blinks with foodcalculateSnake(); // calculates snake parametershandleGameStates();// uncomment this if you want the current game board to be printed to the serial (slows down the game a bit)// dumpGameBoard();}// --------------------------------------------------------------- //// -------------------- supporting variables --------------------- //// --------------------------------------------------------------- //LedControl matrix(Pin::DIN, Pin::CLK, Pin::CS, 1);struct Point {int row = 0, col = 0;Point(int row = 0, int col = 0): row(row), col(col) {}};struct Coordinate {int x = 0, y = 0;Coordinate(int x = 0, int y = 0): x(x), y(y) {}};bool win = false;bool gameOver = false;// primary snake head coordinates (snake head), it will be randomly generatedPoint snake;// food is not anywhere yetPoint food(-1, -1);// construct with default values in case the user turns off the calibrationCoordinate joystickHome(500, 500);// snake parametersint snakeLength = initialSnakeLength; // choosed by the user in the config sectionint snakeSpeed = 1; // will be set according to potentiometer value, cannot be 0int snakeDirection = 0; // if it is 0, the snake does not move// direction constantsconst short up = 1;const short right = 2;const short down = 3; // 'down - 2' must be 'up'const short left = 4; // 'left - 2' must be 'right'// threshold where movement of the joystick will be acceptedconst int joystickThreshold = 160;// artificial logarithmity (steepness) of the potentiometer (-1 = linear, 1 = natural, bigger = steeper (recommended 0...1))const float logarithmity = 0.4;// snake body segments storageint gameboard[8][8] = {};// --------------------------------------------------------------- //// -------------------------- functions -------------------------- //// --------------------------------------------------------------- //// if there is no food, generate one, also check for victoryvoid generateFood() {if (food.row == -1 || food.col == -1) {// self-explanatoryif (snakeLength >= 64) {win = true;return; // prevent the food generator from running, in this case it would run forever, because it will not be able to find a pixel without a snake}// generate food until it is in the right positiondo {food.col = random(8);food.row = random(8);} while (gameboard[food.row][food.col] > 0);}}// watches joystick movements & blinks with foodvoid scanJoystick() {int previousDirection = snakeDirection; // save the last directionlong timestamp = millis();while (millis() < timestamp + snakeSpeed) {// calculate snake speed exponentially (10...1000ms)float raw = mapf(analogRead(Pin::potentiometer), 0, 1023, 0, 1);snakeSpeed = mapf(pow(raw, 3.5), 0, 1, 10, 1000); // change the speed exponentiallyif (snakeSpeed == 0) snakeSpeed = 1; // safety: speed can not be 0// determine the direction of the snakeanalogRead(Pin::joystickY) < joystickHome.y - joystickThreshold ? snakeDirection = up : 0;analogRead(Pin::joystickY) > joystickHome.y + joystickThreshold ? snakeDirection = down : 0;analogRead(Pin::joystickX) < joystickHome.x - joystickThreshold ? snakeDirection = left : 0;analogRead(Pin::joystickX) > joystickHome.x + joystickThreshold ? snakeDirection = right : 0;// ignore directional change by 180 degrees (no effect for non-moving snake)snakeDirection + 2 == previousDirection && previousDirection != 0 ? snakeDirection = previousDirection : 0;snakeDirection - 2 == previousDirection && previousDirection != 0 ? snakeDirection = previousDirection : 0;// intelligently blink with the foodmatrix.setLed(0, food.row, food.col, millis() % 100 < 50 ? 1 : 0);}}// calculate snake movement datavoid calculateSnake() {switch (snakeDirection) {case up:snake.row--;fixEdge();matrix.setLed(0, snake.row, snake.col, 1);break;case right:snake.col++;fixEdge();matrix.setLed(0, snake.row, snake.col, 1);break;case down:snake.row++;fixEdge();matrix.setLed(0, snake.row, snake.col, 1);break;case left:snake.col--;fixEdge();matrix.setLed(0, snake.row, snake.col, 1);break;default: // if the snake is not moving, exitreturn;}// if there is a snake body segment, this will cause the end of the game (snake must be moving)if (gameboard[snake.row][snake.col] > 1 && snakeDirection != 0) {gameOver = true;return;}// check if the food was eatenif (snake.row == food.row && snake.col == food.col) {food.row = -1; // reset foodfood.col = -1;// increment snake lengthsnakeLength++;// increment all the snake body segmentsfor (int row = 0; row < 8; row++) {for (int col = 0; col < 8; col++) {if (gameboard[row][col] > 0 ) {gameboard[row][col]++;}}}}// add new segment at the snake head locationgameboard[snake.row][snake.col] = snakeLength + 1; // will be decremented in a moment// decrement all the snake body segments, if segment is 0, turn the corresponding led offfor (int row = 0; row < 8; row++) {for (int col = 0; col < 8; col++) {// if there is a body segment, decrement it's valueif (gameboard[row][col] > 0 ) {gameboard[row][col]--;}// display the current pixelmatrix.setLed(0, row, col, gameboard[row][col] == 0 ? 0 : 1);}}}// causes the snake to appear on the other side of the screen if it gets out of the edgevoid fixEdge() {snake.col < 0 ? snake.col += 8 : 0;snake.col > 7 ? snake.col -= 8 : 0;snake.row < 0 ? snake.row += 8 : 0;snake.row > 7 ? snake.row -= 8 : 0;}void handleGameStates() {if (gameOver || win) {unrollSnake();showScoreMessage(snakeLength - initialSnakeLength);if (gameOver) showGameOverMessage();else if (win) showWinMessage();// re-init the gamewin = false;gameOver = false;snake.row = random(8);snake.col = random(8);food.row = -1;food.col = -1;snakeLength = initialSnakeLength;snakeDirection = 0;memset(gameboard, 0, sizeof(gameboard[0][0]) * 8 * 8);matrix.clearDisplay(0);}}void unrollSnake() {// switch off the food LEDmatrix.setLed(0, food.row, food.col, 0);delay(800);// flash the screen 5 timesfor (int i = 0; i < 5; i++) {// invert the screenfor (int row = 0; row < 8; row++) {for (int col = 0; col < 8; col++) {matrix.setLed(0, row, col, gameboard[row][col] == 0 ? 1 : 0);}}delay(20);// invert it backfor (int row = 0; row < 8; row++) {for (int col = 0; col < 8; col++) {matrix.setLed(0, row, col, gameboard[row][col] == 0 ? 0 : 1);}}delay(50);}delay(600);for (int i = 1; i <= snakeLength; i++) {for (int row = 0; row < 8; row++) {for (int col = 0; col < 8; col++) {if (gameboard[row][col] == i) {matrix.setLed(0, row, col, 0);delay(100);}}}}}// calibrate the joystick home for 10 timesvoid calibrateJoystick() {Coordinate values;for (int i = 0; i < 10; i++) {values.x += analogRead(Pin::joystickX);values.y += analogRead(Pin::joystickY);}joystickHome.x = values.x / 10;joystickHome.y = values.y / 10;}void initialize() {pinMode(Pin::joystickVCC, OUTPUT);digitalWrite(Pin::joystickVCC, HIGH);pinMode(Pin::joystickGND, OUTPUT);digitalWrite(Pin::joystickGND, LOW);matrix.shutdown(0, false);matrix.setIntensity(0, intensity);matrix.clearDisplay(0);randomSeed(analogRead(A5));snake.row = random(8);snake.col = random(8);}void dumpGameBoard() {String buff = "\n\n\n";for (int row = 0; row < 8; row++) {for (int col = 0; col < 8; col++) {if (gameboard[row][col] < 10) buff += " ";if (gameboard[row][col] != 0) buff += gameboard[row][col];else if (col == food.col && row == food.row) buff += "@";else buff += "-";buff += " ";}buff += "\n";}Serial.println(buff);}// --------------------------------------------------------------- //// -------------------------- messages --------------------------- //// --------------------------------------------------------------- //const PROGMEM bool snakeMessage[8][84] = {{0,0,0,0,0,0,0,0, 0,1,1,0,0,0,0,1,1,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},{0,0,0,0,0,0,0,0, 0,1,1,1,0,0,1,1,1,0,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0},{0,0,0,0,0,0,0,0, 0,1,1,0,1,1,0,1,1,0,1,1,0,0,0,1,0,0,0,0,0,0,0,0,1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},{0,0,0,0,0,0,0,0, 0,1,1,0,1,1,0,1,1,0,1,1,0,0,0,1,0,0,0,0,0,0,0,0,1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},{0,0,0,0,0,0,0,0, 0,1,1,0,1,1,0,1,1,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},{0,0,0,0,0,0,0,0, 0,1,1,0,1,1,0,1,1,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},{0,0,0,0,0,0,0,0, 0,1,1,0,0,0,0,1,1,0,1,1,0,0,1,0,0,0,0,1,1,0,0,0,1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},{0,0,0,0,0,0,0,0, 0,1,1,0,0,0,0,1,1,0,1,1,0,0,0,1,0,0,0,1,1,0,0,0,1, 0,1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}};const PROGMEM bool gameOverMessage[8][90] = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},{0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0},{0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0},{0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0},{0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0},{0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0},{0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},{0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}};const PROGMEM bool scoreMessage[8][58] = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},{0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},{0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0},{0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0},{0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0},{0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0},{0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};const PROGMEM bool digits[][8][8] = {{{0, 0, 0, 0, 0, 0, 0, 0},{0, 0, 1, 1, 1, 1, 0, 0},{0, 1, 1, 0, 0, 1, 1, 0},{0, 1, 1, 0, 1, 1, 1, 0},{0, 1, 1, 1, 0, 1, 1, 0},{0, 1, 1, 0, 0, 1, 1, 0},{0, 1, 1, 0, 0, 1, 1, 0},{0, 0, 1, 1, 1, 1, 0, 0}},{{0, 0, 0, 0, 0, 0, 0, 0},{0, 0, 0, 1, 1, 0, 0, 0},{0, 0, 0, 1, 1, 0, 0, 0},{0, 0, 1, 1, 1, 0, 0, 0},{0, 0, 0, 1, 1, 0, 0, 0},{0, 0, 0, 1, 1, 0, 0, 0},{0, 0, 0, 1, 1, 0, 0, 0},{0, 1, 1, 1, 1, 1, 1, 0}},{{0, 0, 0, 0, 0, 0, 0, 0},{0, 0, 1, 1, 1, 1, 0, 0},{0, 1, 1, 0, 0, 1, 1, 0},{0, 0, 0, 0, 0, 1, 1, 0},{0, 0, 0, 0, 1, 1, 0, 0},{0, 0, 1, 1, 0, 0, 0, 0},{0, 1, 1, 0, 0, 0, 0, 0},{0, 1, 1, 1, 1, 1, 1, 0}},{{0, 0, 0, 0, 0, 0, 0, 0},{0, 0, 1, 1, 1, 1, 0, 0},{0, 1, 1, 0, 0, 1, 1, 0},{0, 0, 0, 0, 0, 1, 1, 0},{0, 0, 0, 1, 1, 1, 0, 0},{0, 0, 0, 0, 0, 1, 1, 0},{0, 1, 1, 0, 0, 1, 1, 0},{0, 0, 1, 1, 1, 1, 0, 0}},{{0, 0, 0, 0, 0, 0, 0, 0},{0, 0, 0, 0, 1, 1, 0, 0},{0, 0, 0, 1, 1, 1, 0, 0},{0, 0, 1, 0, 1, 1, 0, 0},{0, 1, 0, 0, 1, 1, 0, 0},{0, 1, 1, 1, 1, 1, 1, 0},{0, 0, 0, 0, 1, 1, 0, 0},{0, 0, 0, 0, 1, 1, 0, 0}},{{0, 0, 0, 0, 0, 0, 0, 0},{0, 1, 1, 1, 1, 1, 1, 0},{0, 1, 1, 0, 0, 0, 0, 0},{0, 1, 1, 1, 1, 1, 0, 0},{0, 0, 0, 0, 0, 1, 1, 0},{0, 0, 0, 0, 0, 1, 1, 0},{0, 1, 1, 0, 0, 1, 1, 0},{0, 0, 1, 1, 1, 1, 0, 0}},{{0, 0, 0, 0, 0, 0, 0, 0},{0, 0, 1, 1, 1, 1, 0, 0},{0, 1, 1, 0, 0, 1, 1, 0},{0, 1, 1, 0, 0, 0, 0, 0},{0, 1, 1, 1, 1, 1, 0, 0},{0, 1, 1, 0, 0, 1, 1, 0},{0, 1, 1, 0, 0, 1, 1, 0},{0, 0, 1, 1, 1, 1, 0, 0}},{{0, 0, 0, 0, 0, 0, 0, 0},{0, 1, 1, 1, 1, 1, 1, 0},{0, 1, 1, 0, 0, 1, 1, 0},{0, 0, 0, 0, 1, 1, 0, 0},{0, 0, 0, 0, 1, 1, 0, 0},{0, 0, 0, 1, 1, 0, 0, 0},{0, 0, 0, 1, 1, 0, 0, 0},{0, 0, 0, 1, 1, 0, 0, 0}},{{0, 0, 0, 0, 0, 0, 0, 0},{0, 0, 1, 1, 1, 1, 0, 0},{0, 1, 1, 0, 0, 1, 1, 0},{0, 1, 1, 0, 0, 1, 1, 0},{0, 0, 1, 1, 1, 1, 0, 0},{0, 1, 1, 0, 0, 1, 1, 0},{0, 1, 1, 0, 0, 1, 1, 0},{0, 0, 1, 1, 1, 1, 0, 0}},{{0, 0, 0, 0, 0, 0, 0, 0},{0, 0, 1, 1, 1, 1, 0, 0},{0, 1, 1, 0, 0, 1, 1, 0},{0, 1, 1, 0, 0, 1, 1, 0},{0, 0, 1, 1, 1, 1, 1, 0},{0, 0, 0, 0, 0, 1, 1, 0},{0, 1, 1, 0, 0, 1, 1, 0},{0, 0, 1, 1, 1, 1, 0, 0}}};// scrolls the 'snake' message around the matrixvoid showSnakeMessage() {[&] {for (int d = 0; d < sizeof(snakeMessage[0]) - 7; d++) {for (int col = 0; col < 8; col++) {delay(messageSpeed);for (int row = 0; row < 8; row++) {// this reads the byte from the PROGMEM and displays it on the screenmatrix.setLed(0, row, col, pgm_read_byte(&(snakeMessage[row][col + d])));}}// if the joystick is moved, exit the messageif (analogRead(Pin::joystickY) < joystickHome.y - joystickThreshold|| analogRead(Pin::joystickY) > joystickHome.y + joystickThreshold|| analogRead(Pin::joystickX) < joystickHome.x - joystickThreshold|| analogRead(Pin::joystickX) > joystickHome.x + joystickThreshold) {return; // return the lambda function}}}();matrix.clearDisplay(0);// wait for joystick co come backwhile (analogRead(Pin::joystickY) < joystickHome.y - joystickThreshold|| analogRead(Pin::joystickY) > joystickHome.y + joystickThreshold|| analogRead(Pin::joystickX) < joystickHome.x - joystickThreshold|| analogRead(Pin::joystickX) > joystickHome.x + joystickThreshold) {}}// scrolls the 'game over' message around the matrixvoid showGameOverMessage() {[&] {for (int d = 0; d < sizeof(gameOverMessage[0]) - 7; d++) {for (int col = 0; col < 8; col++) {delay(messageSpeed);for (int row = 0; row < 8; row++) {// this reads the byte from the PROGMEM and displays it on the screenmatrix.setLed(0, row, col, pgm_read_byte(&(gameOverMessage[row][col + d])));}}// if the joystick is moved, exit the messageif (analogRead(Pin::joystickY) < joystickHome.y - joystickThreshold|| analogRead(Pin::joystickY) > joystickHome.y + joystickThreshold|| analogRead(Pin::joystickX) < joystickHome.x - joystickThreshold|| analogRead(Pin::joystickX) > joystickHome.x + joystickThreshold) {return; // return the lambda function}}}();matrix.clearDisplay(0);// wait for joystick co come backwhile (analogRead(Pin::joystickY) < joystickHome.y - joystickThreshold|| analogRead(Pin::joystickY) > joystickHome.y + joystickThreshold|| analogRead(Pin::joystickX) < joystickHome.x - joystickThreshold|| analogRead(Pin::joystickX) > joystickHome.x + joystickThreshold) {}}// scrolls the 'win' message around the matrixvoid showWinMessage() {// not implemented yet // TODO: implement it}// scrolls the 'score' message with numbers around the matrixvoid showScoreMessage(int score) {if (score < 0 || score > 99) return;// specify score digitsint second = score % 10;int first = (score / 10) % 10;[&] {for (int d = 0; d < sizeof(scoreMessage[0]) + 2 * sizeof(digits[0][0]); d++) {for (int col = 0; col < 8; col++) {delay(messageSpeed);for (int row = 0; row < 8; row++) {if (d <= sizeof(scoreMessage[0]) - 8) {matrix.setLed(0, row, col, pgm_read_byte(&(scoreMessage[row][col + d])));}int c = col + d - sizeof(scoreMessage[0]) + 6; // move 6 px in front of the previous message// if the score is < 10, shift out the first digit (zero)if (score < 10) c += 8;if (c >= 0 && c < 8) {if (first > 0) matrix.setLed(0, row, col, pgm_read_byte(&(digits[first][row][c]))); // show only if score is >= 10 (see above)} else {c -= 8;if (c >= 0 && c < 8) {matrix.setLed(0, row, col, pgm_read_byte(&(digits[second][row][c]))); // show always}}}}// if the joystick is moved, exit the messageif (analogRead(Pin::joystickY) < joystickHome.y - joystickThreshold|| analogRead(Pin::joystickY) > joystickHome.y + joystickThreshold|| analogRead(Pin::joystickX) < joystickHome.x - joystickThreshold|| analogRead(Pin::joystickX) > joystickHome.x + joystickThreshold) {return; // return the lambda function}}}();matrix.clearDisplay(0);// // wait for joystick co come back// while (analogRead(Pin::joystickY) < joystickHome.y - joystickThreshold// || analogRead(Pin::joystickY) > joystickHome.y + joystickThreshold// || analogRead(Pin::joystickX) < joystickHome.x - joystickThreshold// || analogRead(Pin::joystickX) > joystickHome.x + joystickThreshold) {}}// standard map function, but with floatsfloat mapf(float x, float in_min, float in_max, float out_min, float out_max) {return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;}
Importância para a Robótica
Este projeto, aparentemente simples, é fundamental para o desenvolvimento de habilidades em:
Programação de Microcontroladores – Aprende-se a manipular entradas (joystick, potenciômetro) e saídas (matriz de LED).
Lógica de Jogos – Desenvolve algoritmos para movimentação, colisão e geração aleatória de eventos.
Eletrônica Básica – Entende-se o funcionamento de componentes como LEDs, resistores e sensores.
Sistemas Embarcados – Aplica conceitos de tempo real (delay controlado por potenciômetro).
Prototipagem Rápida – Incentiva a criação de projetos interativos, essenciais para robótica educacional.
Conclusão
Implementar o jogo Snake no Arduino usando uma matriz de LED 8x8, joystick e potenciômetro é um excelente exercício para iniciantes em robótica e programação. Além de ser divertido, esse projeto consolida conhecimentos essenciais para o desenvolvimento de sistemas mais complexos, como robôs autônomos e interfaces homem-máquina.
Obrigado Marcao! consegui!!
ResponderExcluir