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)