Arduino Projekt: Pong Spiel
Autor: Justin Frommberger
Aufgabenstellung
- Das Ziel dieses Projektes ist eigenes Pong spiel umzusetzen.
- Ein Punkt (Ball) bewegt sich auf dem Bildschirm hin und her.
- Jeder der beiden Spieler steuert einen senkrechten Strich (Schläger), den er mit einem Drehknopf (Paddle) nach oben und unten verschieben kann.
- Lässt man den „Ball“ am „Schläger“ vorbei und berührt die Wand, erhält der Gegner einen Punkt.
Benötigte Software
- Aktuellste Arduino IDE mit der Version für ihren PC. (Download link)
- Bibliotheken für das OLED Display: Adafruit_SSD1306 und Adafruit-GFX-Library downloaden.
- Klicke oben rechts in GitHub auf Code und dann downloade die Zip-Datei.
- Um die Zip-Datei in ihre Arduino Bibliothek einzubinden, folgen diese Schritte: (Link)
Benötigte Materiallien
Tabelle 1: Materialliste
Nr. | Anz. | Beschreibung | Bild | Pos. | Anz. | Beschreibung | Bild |
---|---|---|---|---|---|---|---|
① | 1 | Funduino Arduino UNO R3 | ② | viele | Jumper Kabel, männlich/männlich | ||
③ | 1 | Steckbrett | ④ | 4 | Taster | ||
⑤ | 1 | 0.96 I2C OLED Display |
Vorab wichtig zu wissen!
Arduino Uno R3:
- Der Arduino besitzt unterschiedliche Schnittstellen, weil der Arduino ein digitaler Mikrocontroller ist, kann er nur 5 Volt ausgeben oder annehmen.
- Bei einer konstanten 5 V Spannung, ist die LED immer gleich hell, so ist das Ziel die Spannung zur LED zu reduzieren.
- Dafür wird eine Pulsweitenmodulation (PWM) Schnittstelle benötigt, denn bei den anderen Schnittstellen ist dies nicht möglich.
- Bei einem geringen PWM-Wert ist das 5 V Signal kaum noch vorhanden und bei einem hohen PWM-Wert liegt das 5 V Signal nahezu durchgehend am Pin an.
- Durch die PWM Schnittstelle kann nun die LED unterschiedlich hell leuchten, da die Spannung anpassbar ist.
- Die [PWM] Schnittstellen sind ganz einfach zu erkennen an diesem Zeichen (~)
Steckbrett:
Erklärung zum Arbeiten mit einem Steckbrett (klicken!)
OLED Display:
Das Display verfügt über vier Pins:
- VCC: Pin für die Spannungsversorgung, anzuschließen an den 5V Pin des Mikrocontrollers
- GND: Ground-Pin, anzuschließen an den GND Pin des Mikrocontrollers
- SDA und SCL: mit den dafür vorgesehenen Kontakten am Mikrocontroller
- Beim UNO R3 gibt es dafür oberhalb des Pin 13 einen SDA und SCL Pin, alternativ können auch die analogen Pins A4 (SDA) und A5 (SCL) verwendet werden.
Aufbau Schaltung
- * In Abb. 3 wird die Schaltung für das Projekt " Arduino Pong Spiel" dargestellt.
Programmierung
Schritt 1
- Erstellen der ersten Arduino Datei (Link zum Tutorial).
Schritt 2
- Kenntnisse in den Programmierrichtlinien für die Erstellung von Software. (Link)
- Grundkenntnisse von Projekt 1-5 verstanden haben. (Link)
- Grundkenntnisse für das Projekt "Arduino Pong Spiel" verstehen. (Link)
Schritt 3
- Nachdem die Schritte 1 und 2 abgeschlossen sind, kann mit der Programmierung des Projektes gestartet werden.
1) Bibliotheken einfügen
Zuerst muss, für das Projekt Pong Spiel die heruntergeladenen Bibliotheken eingefügt werden.
Benötigt wird:
- Kommunikation zum I2C/TWI Gerät.
- Kommunikation mit dem SPI Gerät.
- Adafruit GFX Grafik.
- 128x64 and 128x32 OLEDs Displays.
Lösung |
// Benötigte Bibliotheken
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
|
2) Initialisierung
Lösung |
/* Konstanten */
const char UP_BUTTON = 2;
const char DOWN_BUTTON = 3;
const char SCREEN_WIDTH = 128; // OLED display Breite, in Pixel
const char SCREEN_HEIGHT = 64; // OLED display Höhe, in Pixel
|
3) Ultraschallsensor
Lösung |
4) Serieller Monitor
5) If-Verzweigung für LEDs und Buzzer
Lösung |
Schritt 4
- Nach dem Beenden von Schritt 3, kann nun das Ergebnis mit der Musterlösung verglichen werden.
Musterlösung
Quelle: Link
Lösung Code |
// Benötigte Bibliotheken
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
/* Konstanten */
const char UP_BUTTON = 2;
const char DOWN_BUTTON = 3;
const char SCREEN_WIDTH = 128; // OLED display Breite, in Pixel
const char SCREEN_HEIGHT = 64; // OLED display Höhe, in Pixel
const unsigned char PADDLE_RATE = 33; // const: Konstant, wert bleibt unverändert
const unsigned char BALL_RATE = 16; // unsigned long: kann keine negativen Zahlen speichern, der Bereich liegt zwischen 0 und 4,294,967,295 (2^32 - 1)
const unsigned char PADDLE_HEIGHT = 25;
// Deklaration für das verwendete Display, verbindung zum I2C (SDA, SCL pins)
const unsigned char OLED_RESET = 4; // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
/* Variablen deklarieren */
unsigned int Player_score = 0, Ai_score = 0;
// Position vom Ball, Paddle und Spieler auf dem Display
unsigned char Ball_x = 64, Ball_y = 32; // UINT8_t == unsigned char
unsigned char Ball_dir_x = 1, Ball_dir_y = 1;
unsigned long Ball_update;
unsigned long Paddle_update;
const unsigned char CPU_X = 12; // Das const-Keywort steht für Konstanten
unsigned char Cpu_y = 16;
const unsigned char PLAYER_X = 115;
unsigned char Player_y = 16;
void setup() {
Serial.begin(9600);
display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // Starte das Display
display.display(); // Display aktualisierung
unsigned long start = millis(); // Gibt die Anzahl von Millisekunden zurück, seit das Arduino-Board das aktuelle Programm gestartet hat
// Taster Initialisieren
pinMode(UP_BUTTON, INPUT);
pinMode(DOWN_BUTTON, INPUT);
digitalWrite(UP_BUTTON, 1);
digitalWrite(DOWN_BUTTON, 1);
display.clearDisplay(); // Display alle pixel ausschalten
while (millis() - start < 2000); // Solange millis kleiner als 2000ms ist
display.display();
Ball_update = millis();
delay(1000);
Paddle_update = Ball_update;
}
// Punkteanzeige
void drawScore() {
// draw AI and player scores
display.setTextSize(2);
display.setTextColor(WHITE);
display.setCursor(45, 0);
display.println(Player_score);
display.setCursor(75, 0);
display.println(Ai_score);
}
// Punkte zurücksetzten
void eraseScore() {
// erase AI and player scores
display.setTextSize(2);
display.setTextColor(BLACK);
display.setCursor(45, 0);
display.println(Player_score);
display.setCursor(75, 0);
display.println(Ai_score);
}
void loop() {
drawScore();
bool update = false; // Ein bool enthält einen von zwei Werten, true oder false
unsigned long time = millis();
static bool Up_state = false;
static bool Down_state = false;
Up_state |= (digitalRead(UP_BUTTON) == LOW); // Taster auslesen
Down_state |= (digitalRead(DOWN_BUTTON) == LOW);
if (time > Ball_update) {
unsigned char New_x = Ball_x + Ball_dir_x; // neue Ball Position
unsigned char New_y = Ball_y + Ball_dir_y;
// Checkt ob die verticalen Wände berüht werden
if (New_x == 0) { // Wand links
Ball_dir_x = -Ball_dir_x; // Wechselt die Richtung
New_x += Ball_dir_x + Ball_dir_x;
eraseScore(); // Punkt für Spieler
Player_score = Player_score + 1;
drawScore();
}
if (New_x == 127) { // Wand rechts
Ball_dir_x = -Ball_dir_x; // Wechselt die Richtung
New_x += Ball_dir_x + Ball_dir_x;
eraseScore(); // Punkt für den Computer
Ai_score = Ai_score + 1;
drawScore();
}
// Checkt ob die horizontalen Wände berüht werden
if (New_y == 0 || New_y == 63) {
Ball_dir_y = -Ball_dir_y; // Wechselt die Richtung
New_y += Ball_dir_y + Ball_dir_y;
}
// Checkt ob der Computer Paddel getroffen wurde
if (New_x == CPU_X && New_y >= Cpu_y && New_y <= Cpu_y + PADDLE_HEIGHT) {
Ball_dir_x = -Ball_dir_x;
New_x += Ball_dir_x + Ball_dir_x;
}
// Checkt ob der Spieler Paddel getroffen wurde
if (New_x == PLAYER_X && New_y >= Player_y && New_y <= Player_y + PADDLE_HEIGHT) {
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; // updated darum bool auf true
}
if (time > Paddle_update) {
Paddle_update += PADDLE_RATE;
// Computer Paddel
display.drawFastVLine(CPU_X, Cpu_y, PADDLE_HEIGHT, BLACK);
const unsigned char Half_paddle = PADDLE_HEIGHT >> 1;
if (Cpu_y + Half_paddle > Ball_y) {
Cpu_y -= 1;
}
if (Cpu_y + Half_paddle < Ball_y) {
Cpu_y += 1;
}
if (Cpu_y < 1) Cpu_y = 1;
if (Cpu_y + PADDLE_HEIGHT > 63) Cpu_y = 63 - PADDLE_HEIGHT;
display.drawFastVLine(CPU_X, Cpu_y, PADDLE_HEIGHT, WHITE);
// Spieler Paddel
display.drawFastVLine(PLAYER_X, Player_y, PADDLE_HEIGHT, BLACK);
if (Up_state) {
Player_y -= 1;
}
if (Down_state) {
Player_y += 1;
}
Up_state = Down_state = false;
if (Player_y < 1) Player_y = 1;
if (Player_y + PADDLE_HEIGHT > 63) Player_y = 63 - PADDLE_HEIGHT;
display.drawFastVLine(PLAYER_X, Player_y, PADDLE_HEIGHT, WHITE);
update = true;
}
if (update)
display.display();
}
|
→ zurück zum Hauptartikel: BA: Arduino-Projekte für die Lehre