Banner do Post - Snackino: O Jogo da Cobrinha Implementado no Arduino Uno

Snackino: O Jogo da Cobrinha Implementado no Arduino Uno

Snackino: O Jogo da Cobrinha Implementado no Arduino Uno

Bem-vindo a mais um projeto emocionante no DevMaker! Hoje, vamos explorar o "Snackino", uma implementação divertida do clássico jogo da cobrinha (Snake) usando hardware Arduino. Este projeto é perfeito para iniciantes em eletrônica e programação, pois combina controle de display gráfico, entrada de joystick e lógica de jogo simples. Usando um Arduino Uno R3, um joystick shield e um módulo display Nokia 5110 (NK5110), você pode recriar esse jogo icônico de forma portátil e interativa.

O objetivo do jogo é controlar a cobrinha para comer os "ovos" (alimentos) que aparecem na tela, crescendo em tamanho enquanto evita colidir com as bordas ou com o próprio corpo. O placar é atualizado em tempo real, e há um registro de recorde!

Exemplo de setup com display Nokia 5110 e joystick em uma placa similar ao Arduino.

Materiais Necessários

Para montar o Snackino, você precisará dos seguintes componentes:

  • Arduino Uno R3
  • Joystick Shield (com botões para direções: up, down, left, right)
  • Módulo Display NK5110 (baseado no PCD8544, o clássico Nokia 5110)
  • Buzzer ou speaker pequeno (conectado ao pino A3 para sons de beep)
  • Cabos jumper (se necessário para conexões personalizadas)
  • Computador com Arduino IDE instalada

Passo a Passo

Configuração Inicial

  1. Baixe e instale a Arduino IDE, se ainda não tiver.
  2. Adicione as bibliotecas necessárias via Gerenciador de Bibliotecas na IDE:
    • Adafruit_GFX
    • Adafruit_PCD8544
  3. Conecte o joystick shield diretamente sobre o Arduino Uno R3 (ele se encaixa nos pinos).
  4. Conecte o display NK5110 aos pinos especificados:
    • CLK: Pino 9
    • DIN: Pino 10
    • DC: Pino 11
    • CE: Pino 13
    • RST: Pino 12
  5. Conecte o speaker ao pino 17 (A3) e ao GND.

Código do Arduino

Aqui está o código completo para o jogo. Copie e cole na Arduino IDE, verifique e carregue para o board.

//Programa: Snake com Arduino Uno
//Alteracoes e adaptacoes: DevMaker
//
//Baseado no codigo original de Abhinav Faujdar *****/
 
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
#include <SPI.h>

// For LCD from DX.com (https://forum.arduino.cc/index.php?topic=322642.0)
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>

// Pinos de conexão com o display
#define RST 12
#define CE  13
#define DC  11
#define DIN  10
#define CLK  9

// Inicializa o objeto do display
Adafruit_PCD8544 display = Adafruit_PCD8544(CLK, DIN, DC, CE, RST);

 
#define LEFT 5
#define DOWN 4
#define RIGHT 3
#define UP 2
#define speakerPin 17
 
//Verifica em qual direcao a cobra esta se movendo
boolean dl = false, dr = false, du = false, dd = false;
 
int x[50], y[50], i, slength, tempx = 10, tempy = 10, xx, yy;
unsigned int high;
uint8_t bh, bl;
int xegg, yegg;
int freq, tb;
int l, r, u, d, p;
unsigned long time = 280, beeptime = 50;
int score = 0, flag = 0;
 
void setup()
{
  Serial.begin(9600);
  display.begin();
 
  //Informacoes iniciais display
  display.setContrast(50);
  display.clearDisplay();
  display.drawRoundRect(0, 0, 84 , 25, 1, 2);
  display.setTextSize(2);
  display.setTextColor(BLACK);
  display.setCursor(12, 6);
  display.println("SNAKE");
  display.setTextSize(1);
  display.setTextColor(BLACK);
  display.setCursor(12, 29);
  display.println("DevMaker");
  display.setCursor(13, 29);
  display.println("DevMaker");
  display.setCursor(0, 40);
  display.println("devmaker.online");
 
  display.display();
  delay(2000);
 
  pinMode(LEFT, INPUT);
  pinMode(RIGHT, INPUT);
  pinMode(UP, INPUT);
  pinMode(DOWN, INPUT);
  pinMode(speakerPin, OUTPUT);
  digitalWrite(LEFT, HIGH);
  digitalWrite(RIGHT, HIGH);
  digitalWrite(UP, HIGH);
  digitalWrite(DOWN, HIGH);
 
  slength = 8;
  xegg = (display.width()) / 2;
  yegg = (display.height()) / 2;
  display.clearDisplay();
  display.drawRect(0, 0, 84, 48, 1);
  display.setCursor(4, 2);
  display.print("P:     R:");
  display.setCursor(22, 2);
  display.print(score);
  display.setCursor(64, 2);
  display.print(high);
  display.drawRect(0, 0, 84, 11, 1);
  //Define coordenadas iniciais
  for (i = 0; i <= slength; i++)
  {
    x[i] = 25 - 3 * i;
    y[i] = 30;
  }
  for (i = 0; i < slength; i++)  //Draw the snake
  {
    display.drawCircle(x[i], y[i], 1, BLACK);
  }
  display.display();
  dr = true;
}
 
void loop()
{
  movesnake();
}
 
void movesnake()
{
  //Leitura do valor dos botoes
  l = digitalRead(LEFT);
  d = digitalRead(DOWN);
  r = digitalRead(RIGHT);
  u = digitalRead(UP);
 
  if (flag == 0)
  {
    direct();
  }
 
  if (millis() % time == 0)
  {
    if (flag == 0)
    {
      if (dr == true) {
        tempx = x[0] + 3;
        tempy = y[0];
      }
      if (dl == true) {
        tempx = x[0] - 3;
        tempy = y[0];
      }
      if (du == true) {
        tempy = y[0] - 3;
        tempx = x[0];
      }
      if (dd == true) {
        tempy = y[0] + 3;
        tempx = x[0];
      }
    }
    flag = 0;
    //Verifica se a cobra esta nas mesmas coordenadas do ovo
    checkgame();
    checkegg();
 
    //Altera as coordenadas de todos os pontos da cobra
    for (i = 0; i <= slength; i++)
    {
      xx = x[i];
      yy = y[i];
      x[i] = tempx;
      y[i] = tempy;
      tempx = xx;
      tempy = yy;
    }
    //Desenha a cobra e o ovo nas novas coordenadas
    drawsnake();
  }
}
 
void checkgame()
{
  for (i = 1; i < slength; i++)
  {
    //Verifica se o recorde foi batido e
    //mostra na tela o novo valor
    high = (((0xff00 + bh) << 8) + bl);
    if (score > high)
    {
      high = score;
      bh = (high >> 8);
      bl = high & 0xff;
      display.fillRect(61, 1, 20, 9, 0);
      display.setCursor(65, 2);
      display.print(high);
    }
    //Verifica se tocou nas bordas
    if ((x[0] <= 1 || x[0] >= 83) || (y[0] <= 12 || y[0] >= 47) || (x[i] == x[0] && y[i] == y[0]) )
    {
      //Jogo terminado. Mostra informacoes na tela
      display.clearDisplay();
      display.fillRoundRect(0, 0, 84 , 31, 1, 2);
      display.setTextColor(WHITE);
      display.setTextSize(2);
      display.setCursor(18, 1);
      display.print("GAME");
      display.setCursor(18, 16);
      display.print("OVER");
      display.setTextColor(BLACK);
      display.setTextSize(1);
      display.setCursor(12, 33);
      display.print("PLACAR");
      display.setCursor(60, 33);
      display.print(score);
      display.setCursor(12, 41);
      display.print("RECORDE");
      display.setCursor(60, 41);
      display.print(high);
      display.display();
      //Aguarda 5 segundos e reinicia o jogo
      delay(5000);
 
      //Apaga a tela
      display.clearDisplay();
      //Retorna aos valores iniciais
      slength = 8;
      score = 0;
      time = 280;
      redraw();
    }
  }
}
 
void checkegg()      //Snake meets egg
{
  //Verifica se a cobra está nas mesmas coordenadas do ovo
  if (x[0] == xegg or x[0] == (xegg + 1) or x[0] == (xegg + 2) or x[0] == (xegg - 1))
  {
    if (y[0] == yegg or y[0] == (yegg + 1) or y[0] == (yegg + 2) or y[0] == (yegg - 1))
    {
      //Incrementa a cobra em uma posição, incrementa o placar e
      //aumenta a velocidade do jogo, diminuindo o tempo
      score += 1;
      display.fillRect(21, 1, 20, 9, 0);
      display.setCursor(22, 2);
      display.print(score);
      slength += 1;
      if (time >= 90)
      {
        time -= 10;
      }
      display.fillRect(xegg, yegg, 3, 3, WHITE);
      display.display();
      beep(35, beeptime);
      //Cria novo ovo em posicao aleatoria
      xegg = random(2, 80);
      yegg = random(15, 40);
    }
  }
}
 
void direct()
{
  //Altera o movimento caso uma tecla tenha sido pressionada
  if (l == LOW and dr == false)
  {
    dl = true; du = false; dd = false;
    //Salva novas coordenadas em Tempx, Tempy
    tempx = x[0] - 3;
    tempy = y[0];
    flag = 1;
  }
  else if (r == LOW and dl == false)
  {
    dr = true; du = false; dd = false;
    tempx = x[0] + 3;
    tempy = y[0];
    flag = 1;
  }
  else if (u == LOW and dd == false)
  {
    du = true; dl = false; dr = false;
    tempy = y[0] - 3;
    tempx = x[0];
    flag = 1;
  }
  else if (d == LOW and du == false)
  {
    dd = true; dl = false; dr = false;
    tempy = y[0] + 3;
    tempx = x[0];
    flag = 1;
  }
}
 
void drawsnake()
{
  display.fillRect(xegg, yegg, 3, 3, BLACK);
  display.drawCircle(x[0], y[0], 1, BLACK);
  display.drawCircle(x[slength], y[slength], 1, WHITE);
  display.display();
}
 
void redraw()
{
  display.drawRect(0, 0, 84, 48, 1);
  display.drawRect(0, 0, 84, 48, 1);
  display.setCursor(4, 2);
  display.print("P:     R:");
  display.drawRect(0, 0, 84, 11, 1);
  display.fillRect(21, 1, 20, 9, 0);
  display.setCursor(22, 2);
  display.print(score);
  display.fillRect(61, 1, 20, 9, 0);
  display.setCursor(65, 2);
  display.print(high);
 
  xegg = (display.width()) / 2;
  yegg = (display.height()) / 2;
  dl = false, dr = false, du = false, dd = false;
  dr = true;
  display.setCursor(4, 2);
  display.print("P:     R:");
  display.drawRect(0, 0, 84, 11, 1);
  //Retorna as coordenadas iniciais
  for (i = 0; i <= slength; i++)
  {
    x[i] = 25 - 3 * i;
    y[i] = 30;
  }
  tempx = 33 - 3 * i;
  tempy = 30;
  display.display();
}
 
void beep (int freq, long tb)
{
  int x;
  long delayAmount = (long)(500 / freq);
  long loopTime = (long)(tb / (delayAmount * 2));
  for (x = 0; x < loopTime; x++)
  {
    digitalWrite(speakerPin, HIGH);
    delay(delayAmount);
    digitalWrite(speakerPin, LOW);
    delay(delayAmount);
  }
  delay(2);
}

Explicação do Código

O código é baseado em uma adaptação do original de Abhinav Faujdar, com alterações para compatibilidade com o display e joystick.

  • Bibliotecas e Definições: Inclui as bibliotecas Adafruit para gerenciar o display gráfico. Define os pinos para o display, joystick e speaker.
  • Setup(): Inicializa o display, configura os pinos como inputs (com pull-up) e desenha a tela inicial com "SNAKE" e créditos. Define a cobrinha inicial com comprimento 8 e posiciona o primeiro ovo.
  • Loop(): Chama a função movesnake() continuamente para atualizar o jogo.
  • movesnake(): Lê os inputs do joystick, atualiza a direção, move a cobrinha a cada intervalo de tempo, verifica colisões e desenha na tela.
  • checkgame(): Verifica se a cobrinha colidiu com bordas ou consigo mesma. Atualiza o recorde e reinicia o jogo após "GAME OVER".
  • checkegg(): Detecta se a cobrinha comeu o ovo, incrementa o score, cresce a cobrinha, acelera o jogo e gera um novo ovo.
  • direct(): Altera a direção da cobrinha com base nos botões pressionados, evitando movimentos reversos.
  • drawsnake(): Desenha o ovo, a cabeça da cobrinha e apaga a cauda para simular movimento.
  • redraw(): Reinicia a tela e posições iniciais após game over.
  • beep(): Gera sons simples no speaker quando come o ovo.

Exemplo de tela do jogo rodando, mostrando a cobrinha e o alimento.

Testando o Projeto

  1. Conecte o Arduino ao computador via USB.
  2. Abra a Arduino IDE, selecione a porta correta e carregue o código.
  3. Após o upload, o display mostrará a tela inicial "SNAKE".
  4. Use o joystick para mover a cobrinha (esquerda, direita, cima, baixo).
  5. Coma os ovos para aumentar o score e o tamanho. O jogo acelera conforme você pontua!
  6. Se colidir, verá "GAME OVER" com placar e recorde. Aguarde 5 segundos para reiniciar.

Divirta-se com o Snackino! Sinta-se à vontade para modificar o código, como adicionar níveis ou melhorar os gráficos. Se tiver dúvidas ou melhorias, compartilhe nos comentários abaixo. Fique ligado no DevMaker para mais projetos Arduino!


Comentários

Nenhum comentário ainda. Seja o primeiro a comentar!

Faça login para adicionar um comentário.