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.
Arduino Datei erstellen
- Erstellen der ersten Arduino Datei (Link zum Tutorial).
Programmierung Vorkenntnisse
- 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)
Programmierung Anleitung
- 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 Arduino
Nachdem hinzufügen der Bibliotheken folgt die Initialisierung der benötigten Pins und Variablen.
Lösung |
/* Konstanten */
const char UP_BUTTON = 2;
const char DOWN_BUTTON = 3;
|
2.1) Taster
Test Text
Lösung |
/* Konstanten */
const char SCREEN_WIDTH = 128; // OLED Display Breite
const char SCREEN_HEIGHT = 64; // OLED Display Höhe
|
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 UP_BUTTON_TWO = 4;
const char DOWN_BUTTON_TWO = 5;
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
const unsigned char PADDLE_HEIGHT = 25;
const char SCREEN_WIDTH = 128; // OLED Display Breite
const char SCREEN_HEIGHT = 64; // OLED Display Höhe
// Deklaration für das verwendete Display, verbindung zum I2C (SDA, SCL pins)
const char OLED_RESET; // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
/* Variablen deklarieren */
unsigned int Player_one = 0, Player_two = 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);
// Taster zwei
pinMode(UP_BUTTON_TWO, INPUT);
pinMode(DOWN_BUTTON_TWO, INPUT);
digitalWrite(UP_BUTTON_TWO,1);
digitalWrite(DOWN_BUTTON_TWO,1);
display.clearDisplay(); // Display alle pixel ausschalten
while(millis() - start < 2000); // Solange millis kleiner als 2000ms ist
display.display();
Ball_update = millis();
delay(1000);
}
// Punkteanzeige
void drawScore() {
display.setTextSize(2);
display.setTextColor(WHITE);
display.setCursor(44, 0);
display.println(Player_one);
display.setCursor(74, 0);
display.println(Player_two);
}
// Punkte zurücksetzten
void eraseScore() {
display.setTextSize(2);
display.setTextColor(BLACK);
display.setCursor(44, 0);
display.println(Player_one);
display.setCursor(74, 0);
display.println(Player_two);
}
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;
static bool Up_state_two = false;
static bool Down_state_two = false;
Up_state |= (digitalRead(UP_BUTTON) == LOW); // Taster auslesen
Down_state |= (digitalRead(DOWN_BUTTON) == LOW);
Up_state_two |= (digitalRead(UP_BUTTON_TWO) == LOW); // Taster auslesen
Down_state_two |= (digitalRead(DOWN_BUTTON_TWO) == 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_one = Player_one + 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
Player_two = Player_two+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
}
display.drawFastVLine(CPU_X, Cpu_y, PADDLE_HEIGHT, BLACK);
if(Up_state_two) {
Cpu_y -= 1;
}
if(Down_state_two) {
Cpu_y += 1;
}
Up_state_two = Down_state_two = false;
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