Arduino Projekt: Pong Spiel: Unterschied zwischen den Versionen
Zur Navigation springen
Zur Suche springen
Zeile 127: | Zeile 127: | ||
| | | | ||
<syntaxhighlight lang="C" style="border: none; background-color: #EFF1C1; font-size:14px"> | <syntaxhighlight lang="C" style="border: none; background-color: #EFF1C1; font-size:14px"> | ||
// Benötigte Bibliotheken | |||
#include <SPI.h> | #include <SPI.h> | ||
#include <Wire.h> | #include <Wire.h> | ||
#include <Adafruit_GFX.h> | #include <Adafruit_GFX.h> | ||
#include <Adafruit_SSD1306.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 | const unsigned char PADDLE_RATE = 33; // const: Konstant, wert bleibt unverändert | ||
const unsigned | 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 | const unsigned char PADDLE_HEIGHT = 25; | ||
// Deklaration für das verwendete Display, verbindung zum I2C (SDA, SCL pins) | // 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); | 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 | // 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 | unsigned long Ball_update; | ||
unsigned long | unsigned long Paddle_update; | ||
const | 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() { | 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; | |||
} | } | ||
void drawScore() { | |||
// Punkteanzeige | |||
void drawScore() { | |||
// draw AI and player scores | // draw AI and player scores | ||
display.setTextSize(2); | display.setTextSize(2); | ||
display.setTextColor(WHITE); | display.setTextColor(WHITE); | ||
display.setCursor(45, 0); | display.setCursor(45, 0); | ||
display.println( | display.println(Player_score); | ||
display.setCursor(75, 0); | display.setCursor(75, 0); | ||
display.println( | display.println(Ai_score); | ||
} | } | ||
void eraseScore() { | // Punkte zurücksetzten | ||
void eraseScore() { | |||
// erase AI and player scores | // erase AI and player scores | ||
display.setTextSize(2); | display.setTextSize(2); | ||
display.setTextColor(BLACK); | display.setTextColor(BLACK); | ||
display.setCursor(45, 0); | display.setCursor(45, 0); | ||
display.println( | display.println(Player_score); | ||
display.setCursor(75, 0); | display.setCursor(75, 0); | ||
display.println( | display.println(Ai_score); | ||
} | } | ||
void loop() { | 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( | } | ||
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); | |||
if(update) | update = true; | ||
} | |||
if (update) | |||
display.display(); | |||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> |
Version vom 18. Juli 2023, 12:03 Uhr
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) Initialisierung
Nachdem das Projekt aufgebaut ist, kann mit der Programmierung begonnen werden.
Zuerst müssen die verwendeten Schnittstellen am Arduino Initialisiert werden.
Tipp: Initialisiert werden müssen, LEDs, Buzzer, Ultraschallsensor und die internen Timer und Variablen.
Lösung |
2) pinMode()
Lösung |
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