Bemerkung

Hallo und willkommen in der SunFounder Raspberry Pi & Arduino & ESP32 Enthusiasten-Gemeinschaft auf Facebook! Tauchen Sie tiefer ein in die Welt von Raspberry Pi, Arduino und ESP32 mit anderen Enthusiasten.

Warum beitreten?

  • Expertenunterstützung: Lösen Sie Nachverkaufsprobleme und technische Herausforderungen mit Hilfe unserer Gemeinschaft und unseres Teams.

  • Lernen & Teilen: Tauschen Sie Tipps und Anleitungen aus, um Ihre Fähigkeiten zu verbessern.

  • Exklusive Vorschauen: Erhalten Sie frühzeitigen Zugang zu neuen Produktankündigungen und exklusiven Einblicken.

  • Spezialrabatte: Genießen Sie exklusive Rabatte auf unsere neuesten Produkte.

  • Festliche Aktionen und Gewinnspiele: Nehmen Sie an Gewinnspielen und Feiertagsaktionen teil.

👉 Sind Sie bereit, mit uns zu erkunden und zu erschaffen? Klicken Sie auf [ hier ] und treten Sie heute bei!

SPIEL - Pong

Dies ist ein einfaches Pong-Spiel, das mit einem OLED-Display und einem Arduino-Board entwickelt wurde. Im Pong-Spiel treten Spieler gegen den Computer an, indem sie einen vertikalen Schläger steuern, um einen hüpfenden Ball zurückzuprallen. Das Ziel ist es, zu verhindern, dass der Ball an der Kante Ihres Schlägers vorbeigeht, sonst erzielt der Gegner Punkte.

Die Spielmechanik kann in folgende Teile unterteilt werden:

  1. Ballbewegung - Der Ball bewegt sich in seiner aktuellen Richtung mit einer festgelegten Geschwindigkeit. Jedes Mal, wenn der Ball mit einem Schläger kollidiert, nimmt seine Geschwindigkeit zu, was das Spiel herausfordernder macht.

  2. Schlägerbewegung - Wird verwendet, um die Bewegung des Balls zu blockieren, der Schläger kann sich nach oben oder unten bewegen. Spieler steuern ihren eigenen Schläger mit Knöpfen, während der Schläger des Computers automatisch der Position des Balls folgt.

  3. Punktzahl - Immer wenn der Ball über den linken oder rechten Rand des Bildschirms hinausgeht, erzielt der entsprechende Spieler oder CPU Punkte.

Benötigte Komponenten

Für dieses Projekt benötigen wir die folgenden Komponenten.

Es ist definitiv praktisch, ein ganzes Kit zu kaufen, hier ist der Link:

Name

ARTIKEL IN DIESEM KIT

LINK

Elite Explorer Kit

300+

Elite Explorer Kit

Sie können sie auch einzeln über die untenstehenden Links kaufen.

KOMPONENTENBESCHREIBUNG

KAUF-LINK

Arduino Uno R4 WiFi

-

Steckbrett

KAUFEN

Jumperkabel

KAUFEN

Widerstand

KAUFEN

OLED-Display-Modul

KAUFEN

Knopf

KAUFEN

Stromversorgungsmodul

-

Verdrahtung

../_images/12_pong_bb.png

Schaltplan

../_images/12_pong_schematic.png

Code

Bemerkung

  • Sie können die Datei 12_pong_oled.ino direkt unter dem Pfad elite-explorer-kit-main\fun_project\12_pong_oled öffnen.

  • Oder kopieren Sie diesen Code in die Arduino IDE.

Bemerkung

Um die Bibliothek zu installieren, verwenden Sie den Arduino-Bibliotheksmanager und suchen Sie nach „Adafruit SSD1306“ und „Adafruit GFX“ und installieren Sie diese.

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}

Wie funktioniert des?

Die Programmstruktur kann in die folgenden fünf Teile unterteilt werden:

  1. Notwendige Bibliotheken importieren - Verwendet zur Steuerung des OLED-Bildschirms und zum Lesen von Tasteneingaben.

  2. Konstanten und globale Variablen definieren:

    Definitionen für OLED-Bildschirmbreite und -höhe. Definitionen für Tasten und OLED-Reset-Pins. Position, Geschwindigkeit, Größe und Richtung des Balls und der Schläger. Punktzahlen für Spieler und CPU.

  3. Initialisierung:

    Initialisieren Sie die serielle Kommunikation, den OLED-Bildschirm und zeigen Sie die anfängliche Oberfläche an. Stellen Sie Tasten als Eingänge ein und verbinden Sie Pull-up-Widerstände. Zeichnen Sie das Spielfeld.

  4. Hauptschleife:

    Lesen Sie die Zustände der Tasten. Bewegen Sie den Ball basierend auf der eingestellten Aktualisierungsrate. Erkennen Sie Kollisionen zwischen dem Ball und den Schlägern oder Wänden und passen Sie die Richtung und Geschwindigkeit des Balls entsprechend an. Aktualisieren Sie den Bildschirm mit Punktzahlen basierend auf Punktereignissen. Aktualisieren Sie die Positionen der Schläger.

  5. Zusätzliche Funktionen:

    crossesPlayerPaddle und crossesCpuPaddle - Wird verwendet, um zu erkennen, ob der Ball mit dem Schläger des Spielers oder der CPU kollidiert.

    drawCourt - Zeichnet das Spielfeld auf dem OLED-Bildschirm.

    displayScore - Zeigt die Punktzahlen des Spielers und der CPU auf dem Bildschirm an.