Jogo de Arco e Flecha no Arduino com LCD 16x2

 

Jogo de Arco e Flecha no Arduino com LCD 16x2

Introdução

Neste artigo, vamos explorar como criar um jogo de arco e flecha simples usando Arduino e um display LCD 16x2, baseado no projeto disponível no Arduino Project Hub. Este projeto é uma ótima maneira de aprender sobre programação de jogos simples, manipulação de displays LCD e uso de botões como controles.

Materiais Necessários

  • 1 Arduino Uno (ou similar)

  • 1 Display LCD 16x2 com módulo I2C

  • 2 botões push-button

  • 1 Potenciômetro 10kΩ (para ajuste de contraste do LCD)

  • Resistores de 10kΩ (para os botões)

  • Protoboard e jumpers

Circuito do Projeto

O circuito é relativamente simples:

  1. Conecte o display LCD ao Arduino via interface I2C (GND-GND, VCC-5V, SDA-A4, SCL-A5)

  2. Conecte dois botões aos pinos digitais (por exemplo, D2 e D6) com resistores pull-down



Explicação do Código

O jogo consiste em controlar um arqueiro na parte inferior da tela que atira flechas para atingir alvos que aparecem aleatoriamente na parte superior.

cpp
Copy
Download

}

#include <LiquidCrystal.h>

const int buttonPin1 = 6;
const int  buttonPin2 = 1;
int button1state = 0;
int button2state = 0;
int arrowRow  = 0;
int newRow = 0;
int sameRowCounter = 0;

LiquidCrystal lcd(12,  11, 5, 4, 3, 2);
byte weakblock[] = {
  B01100,
  B01100,
  B01100,
  B01100,
  B01100,
  B01100,
  B01100,
  B01100
};
byte strongblock[]  = {
  B00000,
  B00000,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B00000
};
byte bow[] = {
  B00000,
  B00110,
  B01110,
  B10010,
  B11111,
  B10010,
  B01110,
  B00110
};
byte bow2[]  = {
  B00100,
  B00110,
  B00110,
  B00101,
  B00101,
  B00110,
  B00110,
  B00100
};
byte arrow[] = {
  B00000,
  B00000,
  B00100,
  B00010,
  B11111,
  B00010,
  B00100,
  B00000
};
byte superarrow[]  = {
  B00000,
  B01000,
  B00100,
  B00110,
  B11111,
  B00110,
  B00100,
  B01000
};

struct OneBlock
{
  int row;
  int col;
  int type;
};

OneBlock blocks[15];
int counter;
int score;
int  scoreCol;
unsigned long prevScoreMillis = 0;
unsigned long prevBlockMillis  = 0;
unsigned long prevArrowMillis = 0;
unsigned long prevSuperMillis = 0;
bool  gameOver = false;
bool superArrow = false;

void setup()
{
  pinMode(buttonPin1,  INPUT);
  pinMode(buttonPin2, INPUT);
  lcd.begin(16, 2);
  lcd.createChar(0,  weakblock);
  lcd.createChar(1, strongblock);
  lcd.createChar(2, bow);
  lcd.createChar(3, bow2);
  lcd.createChar(4, arrow);
  lcd.createChar(5,  superarrow);
  randomSeed(analogRead(0));
  arrowRow = 0;
  superArrow  = false;
  score = 0;
  counter = 0;
  blocks[0].row = random(0, 2);
  blocks[0].col = 15;
  for (int i = 0; i < 15; ++i)
    blocks[i].row = -1;
}

void  EndGame()
{
  lcd.clear();
  lcd.setCursor(3, 0);
  lcd.print("Game  Over");
  lcd.setCursor(3, 1);
  lcd.print("Score:");
  lcd.setCursor(9,  1);
  lcd.print(score);
  gameOver = true;
}

void IncrementScore()
{
  score++;
  if (score > 9999)
    scoreCol = 11;
  else if (score > 999)
    scoreCol = 12;
  else if (score > 99)
    scoreCol = 13;
  else if  (score > 9)
    scoreCol = 14;
  else
    scoreCol = 15;
}

void  loop()
{
  if (gameOver)
  {
    button1state = digitalRead(buttonPin1);
    button2state = digitalRead(buttonPin2);
    if (button1state == HIGH || button2state  == HIGH)
    {
      gameOver = false;
      delay(1000);
      setup();
    }
    else
      return;
  }

  unsigned long currentMillis =  millis();
  button1state = digitalRead(buttonPin1);
  button2state = digitalRead(buttonPin2);

  if (currentMillis - prevArrowMillis >= 450)
  {
    if (button1state ==  HIGH && !superArrow)
    {
      lcd.setCursor(1, arrowRow);
      lcd.print("  ");
      if (arrowRow == 0)
      {
        arrowRow = 1;
        prevArrowMillis  = currentMillis;
      }
      else if (arrowRow == 1)
      {
        arrowRow  = 0;
        prevArrowMillis = currentMillis;
      }
    }
  }

  if (currentMillis - prevSuperMillis >= 450)
  {
    if (button2state ==  HIGH)
    {
      superArrow = !superArrow;
      prevSuperMillis = currentMillis;
    }
  }

  if (currentMillis - prevScoreMillis >= 1000)
  {
    prevScoreMillis  = currentMillis;
    IncrementScore();
  }

  bool redraw = false;
  if (score > 9999 && currentMillis - prevBlockMillis >= 1)
  {
    prevBlockMillis  = currentMillis;
    redraw = true;
  }
  else if (score > 500 && currentMillis  - prevBlockMillis >= 200)
  {
    prevBlockMillis = currentMillis;
    redraw  = true;
  }
  else if (score > 99 && currentMillis - prevBlockMillis >= 350)
  {
    prevBlockMillis = currentMillis;
    redraw = true;
  }
  else  if (score > 9 && currentMillis - prevBlockMillis >= 450)
  {
    prevBlockMillis  = currentMillis;
    redraw = true;
  }
  else if (currentMillis - prevBlockMillis  >= 500)
  {
    prevBlockMillis = currentMillis;
    redraw = true;
  }

  if (score > 0)
  {
    lcd.setCursor(scoreCol, 0);
    lcd.print(score);
  }

  if (score >= 5)
  {
    lcd.setCursor(1, arrowRow);
    if  (superArrow)
      lcd.write(byte(5));
    else
      lcd.write(byte(4));
  }

  if (score < 5)
  {
    lcd.setCursor(0, 0);
    lcd.write(byte(2));
  }

  if (score == 10)
  {
    lcd.setCursor(0, 0);
    lcd.print("  ");
  }

  if (score < 10 && score >= 5)
  {
    lcd.setCursor(0,  0);
    lcd.write(byte(3));
  }

  if (!redraw)
    return;

  lcd.clear();

  for (int i = 0; i < 15; ++i)
  {
    if (blocks[i].row  != -1)
    {
      lcd.setCursor(blocks[i].col, blocks[i].row);
      lcd.write(byte(blocks[i].type));
      blocks[i].col--;
      if (blocks[i].col < 0)
      {
        if  (arrowRow == blocks[i].row)
        {
          if (!superArrow || superArrow  && blocks[i].type == 1)
          {
            EndGame();
            return;
          }
        }
        blocks[i].row = -1;
      }

      if  (superArrow && arrowRow == blocks[i].row && blocks[i].col == 1 && blocks[i].type  == 0)
      {
        IncrementScore();
        blocks[i].row = -1;
      }
    }
  }
  if (sameRowCounter > 0)
  {
    counter++;
    if (counter == 15)
      counter = 0;
    blocks[counter].row = newRow;
    blocks[counter].col = 15;
    blocks[counter].type = random(0, 2);
    sameRowCounter--;
  }
  else
  {
    sameRowCounter = random(1, 5);
    if (newRow ==  1)
      newRow = 0;
    else
      newRow = 1;
  }
}

Funcionamento do Jogo

  1. Controles:

O JOgo possui dois botões, um deles move a flecha para cima e para baixo e o outro transforma a flecha em uma super flecha que pode destruir os alvos (blocos) mais finos. O objetivo é desviar dos blocos.
  1. Mecânicas:

    • O alvo aparece aleatoriamente na linha superior

    • O jogador deve posicionar o arqueiro e atirar para acertar o alvo

    • Cada acerto aumenta a pontuação

    • O jogo termina quando o jogador erra um certo número de vezes (não implementado neste exemplo básico)

Melhorias Possíveis

  1. Adicionar vidas/limite de erros

  2. Implementar diferentes níveis de dificuldade

  3. Adicionar múltiplos alvos simultâneos

  4. Incluir animações mais elaboradas

  5. Armazenar a pontuação máxima na EEPROM

  6. Adicionar um menu inicial

Conclusão

Este projeto demonstra como criar um jogo simples mas divertido usando componentes básicos com Arduino. Ele combina conceitos importantes como leitura de entradas digitais, controle de displays LCD e lógica de jogos. É um excelente ponto de partida para quem quer aprender desenvolvimento de jogos em hardware embarcado.

Para versões mais avançadas, você pode considerar adicionar um display gráfico ou mesmo componentes físicos como um sensor de flexão para simular o movimento de puxar o arco.

Comentários

Postagens mais visitadas