Jogo Pong com Arduino Uno e tela OLED

Hoje estamos de volta com outro projeto interessante que você pode fazer com a ajuda do Arduino Uno e estamos usando um display OLED. Esse projeto envolve alguns algoritmos e lógicas complexos, o que o torna mais interessante. O nome desse projeto é Pong Game com Arduino e você pode ter brincado com ele na sua infância nas Lojas de Fliperama.

Hoje, vamos recriar esse jogo em uma placa Arduino e aprenderemos como ele foi criado. Esse jogo não é complicado, mas é um pouco desafiador e interessante de desenvolver e jogar.

Esse jogo de pong com Arduino é jogado por dois jogadores e ambos controlam a direção da raquete com os joysticks fornecidos no Arduino Uno. O placar de pontuação é mostrado no meio e uma campainha também está conectada ao Arduino para emitir os sons de pontuação, vitória e derrota.

Estamos usando uma tela OLED de 0,96 polegada e seu tamanho é de 128×64 pixels. Vamos escrever o código para controlar as pás com os joysticks.

Componentes necessários para o jogo Pong com Arduino

Arduino Uno
OLED  0.96 inch
Buzzer
2 x Joystick Ky-023
ProtoBoard
Jumper Wire

Tela OLED

Estamos usando a tela OLED SSD1306 de 0,96 polegadas I2C com o Arduino. O Módulo de Tela OLED (Diodo Orgânico Emissor de Luz) de 4 Pinos – Cor Branca é um módulo OLED branco pequeno e preciso que pode ser conectado a qualquer microcontrolador usando o protocolo I2C/IIC. Ele tem uma resolução de 128×64.

O display OLED não contém nenhuma luz de fundo, o que resulta em um bom contraste de cores, e os displays OLED consomem menos energia em comparação com outros displays. O display OLED que estamos usando consiste em apenas 4 pinos. Existem outros módulos OLED que contêm mais pinos.

As características deste módulo de tela são alto brilho, autoemissão, alta taxa de contraste, amplo ângulo de visão e ampla faixa de temperatura. A tela OLED opera em 3,3V ~ 6V. Nível de entrada/saída compatível: 3,3V, 5V.

Esse módulo de display OLED só precisa de 2 portas de entrada/saída para ser controlado. Ele pode operar em diferentes temperaturas, de -30 graus Celsius a 70 graus Celsius.

Joystick

Você já deve ter visto o joystick em muitos dispositivos, como em consoles de jogos, controladores de brinquedos ou também em grandes veículos e máquinas. O joystick é composto por dois potenciômetros e um botão localizado abaixo deles.

Agora, como ele é composto de dois potenciômetros e um potenciômetro controla o movimento do eixo x e o outro controla o movimento do eixo y, seus valores analógicos estão entre 0 e 1023.

O valor digital do botão de pressão é ALTO OU BAIXO. O joystick está no centro, ou seja, em sua posição natural nas coordenadas de (0,0).

Pinagem

  • Pino GND: conecta-se ao pino GND do Arduino
  • Pino VCC: conecta-se ao pino de 5V do Arduino
  • Pino VRX: Fornece valor analógico entre 0 e 1023 ao longo do eixo x.
  • Pino VRY: Fornece valor analógico entre 0 e 1023 ao longo do eixo y.
  • Pino SW: É a saída do botão de pressão que está dentro do joystick.

Como funciona?

Quando você empurra a alavanca do joystick para a esquerda e para a direita, a tensão muda, a faixa de tensão está entre 0 V e 5 V, 0 à esquerda e 5 V à direita. Obtemos essa alteração no valor da tensão na forma analógica.

O mesmo acontece ao mover o joystick para cima e para baixo, obtemos 0V na parte superior e 5V na parte inferior. O botão de pressão fornece apenas os valores HIGH ou LOW.

Diagrama de circuito do jogo Pong com Arduino

Jogo de pong com conexões do Arduino explicadas

VRx do joystick esquerdo – Fio azul claro – A0
VRx do joystick direito – Fio amarelo – A1
SW do joystick direito – Pino digital 4
Buzzer – Pino digital 10
Oled SCK – Fio verde (I2C) – A5
Oled SDA – Fio azul (I2C) – A4

Código para jogo de pong com Arduino

#include  <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

const  int SW_pin = 4; // digital pin connected to switch output
const int player1 =  A1; // analog pin connected to Y output
const int player2 = A0; // analog pin  connected to Y output

const unsigned long PADDLE_RATE = 45;
const unsigned  long BALL_RATE = 0;
const uint8_t PADDLE_HEIGHT = 12;
int player1Score = 0;
int  player2Score = 0;
int maxScore = 8;
int BEEPER = 10;
bool resetBall = false;
#define  SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 //  OLED display height, in pixels
#define RESET_BUTTON 3
// Declaration for an  SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET     4 //  Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH,  SCREEN_HEIGHT, &Wire, OLED_RESET);

void drawCourt();
void drawScore();

uint8_t  ball_x = 64, ball_y = 32;
uint8_t ball_dir_x = 1, ball_dir_y = 1;
unsigned  long ball_update;

unsigned long paddle_update;
const uint8_t PLAYER2_X  = 22;
uint8_t player2_y = 26;

const uint8_t PLAYER_X = 105;
uint8_t  player1_y = 26;

void setup() {
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.display();
  unsigned long start = millis();
  pinMode(BEEPER, OUTPUT);
  pinMode(SW_pin, INPUT);
  pinMode(RESET_BUTTON, INPUT_PULLUP);
  digitalWrite(SW_pin,  HIGH);
  display.clearDisplay();
  drawCourt();
  drawScore();
  while  (millis() - start < 2000);

  display.display();

  ball_update = millis();
  paddle_update = ball_update;
}

void loop() {
  bool update = false;
  unsigned long time = millis();

  static bool up_state = false;
  static  bool down_state = false;


  if (resetBall)
  {
    if (player1Score  == maxScore || player2Score == maxScore)
    {
      gameOver();
    }
    else {
      display.fillScreen(BLACK);
      drawScore();
      drawCourt();
      ball_x = random(45, 50);
      ball_y = random(23, 33);
      do
      {
        ball_dir_x = random(-1, 2);
      } while (ball_dir_x == 0);

      do
      {
        ball_dir_y = random(-1, 2);
      } while (ball_dir_y  == 0);


      resetBall = false;
    }
  }


  //up_state  |= (digitalRead(UP_BUTTON) == LOW);
  // down_state |= (digitalRead(DOWN_BUTTON)  == LOW);

  if (time > ball_update) {
    uint8_t new_x = ball_x + ball_dir_x;
    uint8_t new_y = ball_y + ball_dir_y;

    // Check if we hit the vertical  walls
    if (new_x == 0 || new_x == 127) {

      if (new_x == 0) {
        player1Score += 1;
        display.fillScreen(BLACK);
        soundPoint();
        resetBall = true;

      }
      else if (new_x == 127) {
        player2Score  += 1;
        display.fillScreen(BLACK);
        soundPoint();
        resetBall  = true;
      }
      ball_dir_x = -ball_dir_x;
      new_x += ball_dir_x  + ball_dir_x;
    }

    // Check if we hit the horizontal walls.
    if  (new_y == 0 || new_y == 63) {
      soundBounce();
      ball_dir_y = -ball_dir_y;
      new_y += ball_dir_y + ball_dir_y;
    }

    // Check if we hit the  player 2 paddle
    if (new_x == PLAYER2_X && new_y >= player2_y && new_y <=  player2_y + PADDLE_HEIGHT) {
      soundBounce();
      ball_dir_x = -ball_dir_x;
      new_x += ball_dir_x + ball_dir_x;
    }

    // Check if we hit the  player 1 paddle
    if (new_x == PLAYER_X && new_y >= player1_y && new_y <= player1_y  + PADDLE_HEIGHT) {
      soundBounce();
      ball_dir_x = -ball_dir_x;
      new_x += ball_dir_x + ball_dir_x;
    }

    display.drawPixel(ball_x,  ball_y, BLACK);
    display.drawPixel(new_x, new_y, WHITE);
    ball_x = new_x;
    ball_y = new_y;

    ball_update += BALL_RATE;

    update = true;
  }

  if (time > paddle_update) {
    paddle_update += PADDLE_RATE;

    //Player 2 paddle
    display.drawFastVLine(PLAYER2_X, player2_y, PADDLE_HEIGHT,  BLACK);
    const uint8_t half_paddle = PADDLE_HEIGHT >> 1;
    if (analogRead(player2)  < 475) {
      player2_y -= 1;
    }
    if (analogRead(player2) > 550)  {
      player2_y += 1;
    }
    if (player2_y < 1) player2_y = 1;
    if (player2_y + PADDLE_HEIGHT > 63) player2_y = 63 - PADDLE_HEIGHT;
    display.drawFastVLine(PLAYER2_X,  player2_y, PADDLE_HEIGHT, WHITE);

    // Player 1 paddle
    display.drawFastVLine(PLAYER_X,  player1_y, PADDLE_HEIGHT, BLACK);
    if (analogRead(player1) < 475) {
      player1_y  -= 1;
    }
    if (analogRead(player1) > 550) {
      player1_y += 1;
    }
    up_state = down_state = false;
    if (player1_y < 1) player1_y  = 1;
    if (player1_y + PADDLE_HEIGHT > 63) player1_y = 63 - PADDLE_HEIGHT;
    display.drawFastVLine(PLAYER_X, player1_y, PADDLE_HEIGHT, WHITE);
  }
  update = true;

  if (update) {
    drawScore();
    display.display();
    if (digitalRead(SW_pin) == 0) //Player pressed button to stop the game
    {
      gameOver(); 
    }
  }
}

void drawCourt() {
  display.drawRect(0,  0, 128, 64, WHITE);
}
void drawScore() {
  // draw players scores
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(45, 0);
  display.println(player2Score);
  display.setCursor(75, 0);
  display.println(player1Score);
}

void  gameOver() { 
  display.fillScreen(BLACK);
  if (player1Score > player2Score)
  {
    display.setCursor(20, 15);
    display.setTextColor(WHITE);
    display.setTextSize(2);
    display.print("Player 1");
    display.setCursor(40, 35);
    display.print("won");
  }
  else
  {
    display.setCursor(20, 15);
    display.setTextColor(WHITE);
    display.setTextSize(2);
    display.print("Player 2");
    display.setCursor(40,  35);
    display.print("won");
  }
  delay(100);
  display.display();
  delay(2000);
  player2Score = player1Score = 0;

  unsigned long start  = millis();
  while (millis() - start < 2000);
  ball_update = millis();
  paddle_update = ball_update;
  resetBall = true;
}
//Sound of ball hitting  wall and paddles
void soundBounce()
{
  tone(BEEPER, 500, 50);
}
//Sound  of point scored
void soundPoint()
{
  tone(BEEPER, 100, 50);
}

Código completo no github (Link)

Please follow and like us:
error0
fb-share-icon
Tweet 20
fb-share-icon20