Nota

Ciao, benvenuto nella community SunFounder Raspberry Pi & Arduino & ESP32 Enthusiasts su Facebook! Approfondisci Raspberry Pi, Arduino ed ESP32 con altri appassionati.

Perché unirsi?

  • Supporto Esperto: Risolvi problemi post-vendita e sfide tecniche con l’aiuto della nostra community e del nostro team.

  • Impara & Condividi: Scambia consigli e tutorial per migliorare le tue competenze.

  • Anteprime Esclusive: Ottieni l’accesso anticipato agli annunci di nuovi prodotti e anteprime esclusive.

  • Sconti Speciali: Goditi sconti esclusivi sui nostri prodotti più recenti.

  • Promozioni e Concorsi Festivi: Partecipa a concorsi e promozioni festive.

👉 Pronto a esplorare e creare con noi? Clicca [Qui] e unisciti oggi stesso!

GIOCO - Pong

Questo è un semplice gioco Pong progettato utilizzando un display OLED e una scheda Arduino. Nel gioco Pong, i giocatori competono contro il computer, controllando una paletta verticale per respingere una palla rimbalzante. L’obiettivo è impedire che la palla superi il bordo della propria paletta, altrimenti l’avversario segna un punto.

Le meccaniche del gioco possono essere suddivise nelle seguenti parti:

  1. Movimento della palla - La palla si muove nella direzione corrente a una velocità impostata. Ogni volta che la palla colpisce una paletta, la sua velocità aumenta, rendendo il gioco più difficile.

  2. Movimento della paletta - Utilizzata per bloccare il movimento della palla, la paletta può muoversi su o giù. I giocatori controllano la propria paletta usando i pulsanti, mentre la paletta del computer segue automaticamente la posizione della palla.

  3. Punteggio - Ogni volta che la palla supera il bordo sinistro o destro dello schermo, il giocatore o il CPU corrispondente segna un punto.

Componenti Necessari

In questo progetto, abbiamo bisogno dei seguenti componenti.

È sicuramente conveniente acquistare un kit completo, ecco il link:

Nome

ELEMENTI IN QUESTO KIT

LINK

Elite Explorer Kit

300+

Elite Explorer Kit

Puoi anche acquistarli separatamente dai link sottostanti.

INTRODUZIONE COMPONENTI

LINK ACQUISTO

Arduino Uno R4 WiFi

-

Breadboard

ACQUISTA

Cavi Jumper

ACQUISTA

Resistenza

ACQUISTA

Modulo Display OLED

ACQUISTA

Pulsante

ACQUISTA

Modulo di Alimentazione

-

Collegamenti

Nota

Per proteggere il Power Pack del Modulo di Alimentazione, caricalo completamente prima di utilizzarlo per la prima volta.

../_images/12_pong_bb.png

Schema Elettrico

../_images/12_pong_schematic.png

Codice

Nota

  • Puoi aprire il file 12_pong_oled.ino nel percorso elite-explorer-kit-main\fun_project\12_pong_oled direttamente.

  • Oppure copia questo codice nell’Arduino IDE.

Nota

Per installare la libreria, usa l’Arduino Library Manager e cerca «Adafruit SSD1306» e «Adafruit GFX» e installale.

12_pong_oled.ino
  1/*
  2  This code creates a basic Pong game using an Arduino Uno, an OLED display, 
  3  and buttons. Players use the buttons to control a vertical paddle and bounce 
  4  back a moving ball to prevent it from passing their paddle. Scoring happens 
  5  when the ball goes off the screen edges.
  6
  7  Board: Arduino Uno R4 
  8  Component: OLED Display Module and Button
  9  Library: https://github.com/adafruit/Adafruit_SSD1306 (Adafruit SSD1306 by Adafruit)  
 10           https://github.com/adafruit/Adafruit-GFX-Library (Adafruit GFX Library by Adafruit) 
 11*/
 12
 13
 14#include <SPI.h>
 15#include <Wire.h>
 16#include <Adafruit_GFX.h>
 17#include <Adafruit_SSD1306.h>
 18
 19#define UP_BUTTON 3
 20#define DOWN_BUTTON 2
 21
 22#define SCREEN_WIDTH 128  // OLED display width, in pixels
 23#define SCREEN_HEIGHT 64  // OLED display height, in pixels
 24
 25// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
 26#define OLED_RESET 4  // Reset pin # (or -1 if sharing Arduino reset pin)
 27Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
 28
 29// ball set
 30const unsigned long BALL_RATE = 16;
 31int ball_x = 64, ball_y = 32;
 32int ball_speed = 1; 
 33int8_t ball_dir_x = 1, ball_dir_y = 1;
 34
 35//flash rate
 36unsigned long ball_update;
 37unsigned long paddle_update;
 38
 39// paddle set
 40const unsigned long PADDLE_RATE = 33;
 41const uint8_t PADDLE_HEIGHT = 16;
 42const uint8_t CPU_X = 12;
 43int8_t cpu_y = 16;
 44const uint8_t PLAYER_X = 115;
 45int8_t player_y = 16;
 46int paddle_speed = 3;
 47
 48// score
 49uint8_t player_score = 0;
 50uint8_t cpu_score = 0;
 51
 52
 53void setup() {
 54  Serial.begin(115200);
 55
 56  randomSeed(analogRead(A0));
 57  ball_dir_x = random(0, 2) * 2 - 1;
 58  ball_dir_y = random(0, 2) * 2 - 1;
 59
 60  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
 61  display.display();
 62
 63  pinMode(UP_BUTTON, INPUT);
 64  pinMode(DOWN_BUTTON, INPUT);
 65
 66  unsigned long start = millis();
 67
 68  display.clearDisplay();
 69  drawCourt();
 70
 71  while (millis() - start < 2000)
 72    ;
 73
 74  displayScore();
 75  display.display();
 76
 77  ball_update = millis();
 78  paddle_update = ball_update;
 79}
 80
 81void loop() {
 82  bool update = false;
 83  unsigned long time = millis();
 84
 85  static bool up_state = false;
 86  static bool down_state = false;
 87
 88  /* check if the button pressed */
 89  up_state |= (digitalRead(UP_BUTTON) == LOW);
 90  down_state |= (digitalRead(DOWN_BUTTON) == LOW);
 91
 92  /* refresh the ball */
 93  if (time > ball_update) {
 94    int new_x = ball_x + ball_dir_x * ball_speed;
 95    int8_t new_y = ball_y + ball_dir_y * ball_speed;
 96
 97    // Check if it hits the horizontal walls.
 98    if (new_y <= 0 || new_y >= SCREEN_HEIGHT - 1) {
 99      ball_dir_y = -ball_dir_y;
100      new_y += ball_dir_y + ball_dir_y * ball_speed;
101      displayScore();
102    }
103
104    // Check if it hits the CPU paddle
105    if (crossesCpuPaddle(ball_x, new_x, ball_y)) {
106      ball_dir_x = -ball_dir_x;
107      new_x = CPU_X + 1;// move the ball's position to the left edge of the paddle
108      ball_speed++;     // speeds up
109    }
110
111    // Check if it hits the player paddle
112    if (crossesPlayerPaddle(ball_x, new_x, ball_y)) {
113      ball_dir_x = -ball_dir_x;
114      new_x = PLAYER_X - 1; // move the ball's position to the right edge of the paddle
115      ball_speed++;         // speeds up
116    }
117
118    // Check if it hits the vertical walls
119    if (new_x <= 0 || new_x >= SCREEN_WIDTH - 1) {
120      if (new_x <= 1) {
121        player_score++;
122      }
123      if (new_x >= 126) {
124        cpu_score++;
125      }
126      /* reset ball */
127      displayScore();
128      ball_speed = 1;  // reset speed
129      new_x = 64; // reset position
130      // new_y = 32;
131      ball_dir_x = (ball_dir_x > 0) ? -1 : 1;     // reset direction
132      ball_dir_y = (random(0, 2) == 0) ? 1 : -1;  // reset direction
133    }
134
135    display.drawPixel(ball_x, ball_y, BLACK);
136    display.drawPixel(new_x, new_y, WHITE);
137    ball_x = new_x;
138    ball_y = new_y;
139
140    ball_update += BALL_RATE; // next refresh time
141    update = true;
142  }
143
144  /* refresh paddles */
145  if (time > paddle_update) {
146    paddle_update += PADDLE_RATE; // next refresh time
147
148    // CPU paddle
149    display.drawFastVLine(CPU_X, cpu_y, PADDLE_HEIGHT, BLACK); //clear paddle
150    const uint8_t half_paddle = PADDLE_HEIGHT >> 1;
151    if (cpu_y + half_paddle > ball_y) {
152      cpu_y -= paddle_speed;
153    }
154    if (cpu_y + half_paddle < ball_y) {
155      cpu_y += paddle_speed;
156    }
157    // constraint position
158    if (cpu_y < 1) cpu_y = 1;
159    if (cpu_y + PADDLE_HEIGHT > 63) cpu_y = 63 - PADDLE_HEIGHT;
160    display.drawFastVLine(CPU_X, cpu_y, PADDLE_HEIGHT, WHITE); //show paddle
161
162    // Player paddle
163    display.drawFastVLine(PLAYER_X, player_y, PADDLE_HEIGHT, BLACK); //clear paddle
164    if (up_state) {
165      player_y -= paddle_speed;
166    }
167    if (down_state) {
168      player_y += paddle_speed;
169    }
170    up_state = down_state = false;
171    // constraint position
172    if (player_y < 1) player_y = 1;
173    if (player_y + PADDLE_HEIGHT > 63) player_y = 63 - PADDLE_HEIGHT;
174    display.drawFastVLine(PLAYER_X, player_y, PADDLE_HEIGHT, WHITE); //show paddle
175    update = true;
176  }
177
178  if (update)
179    display.display();
180}
181
182bool crossesPlayerPaddle(uint8_t old_x, uint8_t new_x, uint8_t ball_y) {
183  return old_x < PLAYER_X && new_x >= PLAYER_X && ball_y >= player_y && ball_y <= player_y + PADDLE_HEIGHT;
184}
185
186bool crossesCpuPaddle(uint8_t old_x, uint8_t new_x, uint8_t ball_y) {
187  return old_x > CPU_X && new_x <= CPU_X && ball_y >= cpu_y && ball_y <= cpu_y + PADDLE_HEIGHT;
188}
189
190void drawCourt() {
191  display.drawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, WHITE);
192}
193
194void displayScore() {
195  display.fillRect(SCREEN_WIDTH / 2 - 20, 10, 60, 10, BLACK);// clear
196  
197  display.setCursor(SCREEN_WIDTH / 2 - 20, 10);  
198  display.setTextSize(1);
199  display.setTextColor(WHITE);
200
201  display.print(cpu_score);
202  display.print(" - ");
203  display.print(player_score);
204}

Come funziona?

La struttura del programma può essere suddivisa nelle seguenti cinque parti:

  1. Importare le Librerie Necessarie - Utilizzate per controllare lo schermo OLED e leggere gli input dei pulsanti.

  2. Definire Costanti e Variabili Globali:

    Definizioni per la larghezza e l’altezza dello schermo OLED. Definizioni per i pulsanti e i pin di reset dell’OLED. Posizione, velocità, dimensione e direzione della palla e delle palette. Punteggi per il giocatore e il CPU.

  3. Inizializzazione:

    Inizializzare la comunicazione seriale, lo schermo OLED e visualizzare l’interfaccia iniziale. Impostare i pulsanti come input e collegare le resistenze pull-up. Disegnare il campo da gioco.

  4. Ciclo Principale:

    Leggere lo stato dei pulsanti. Muovere la palla in base alla frequenza di aggiornamento impostata. Rilevare le collisioni tra la palla e le palette o i muri, regolando la direzione e la velocità della palla di conseguenza. Aggiornare lo schermo con i punteggi in base agli eventi di punteggio. Aggiornare le posizioni delle palette.

  5. Funzioni Aggiuntive:

    crossesPlayerPaddle e crossesCpuPaddle - Utilizzate per rilevare se la palla collide con la paletta del giocatore o del CPU.

    drawCourt - Disegna il campo da gioco sullo schermo OLED.

    displayScore - Visualizza i punteggi del giocatore e del CPU sullo schermo.