Arduino Projekt: Pong Spiel: Unterschied zwischen den Versionen

Aus HSHL Mechatronik
Zur Navigation springen Zur Suche springen
 
(357 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt)
Zeile 1: Zeile 1:
[[Datei:Ultrasonic Security System.jpg|thumb|rigth|250px|Abb. 1: LED Würfel]]
[[Kategorie:Arduino: Projekt]]
'''Autor:''' Justin Frommberger<br/>
[[Datei:PongGame neu.gif|thumb|right|500px|Abb. 1: Pong Spiel]]
== '''Aufgabenstellung''' ==
'''Autor:''' Justin Frommberger<br>
* Das Ziel dieses Projektes ist eignes Pong spiel umzusetzten.<br>
* Pong ist simpel und ähnelt dem des Tischtennis.<br>
* 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, erhält der Gegner einen Punkt.


{| role="presentation" class="wikitable mw-collapsible mw-collapsed"
== Aufgabenstellung==
| <strong>Video &thinsp;</strong>
Das Ziel dieses Projektes ist, ein 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 zwei Tastern nach oben und unten steuern kann.  
[[Datei:Ultrasonic Security System Vid.mp4|600px]]
* Wenn die linke oder rechte Wand berührt wird, erhält der Gegner einen Punkt.<br>
|}


[[Datei:OLED 0.96.png|thumb|rigth|250px|Abb. 2: OLED Display]]
⇒ Für den Fall, dass '''kein Arduino''' zur Verfügung steht oder '''Materialien''' nicht vorhanden sind. Kann dieser '''webbasierter Arduino Emulator''' verwendet werden. [https://wokwi.com/projects/new/arduino-uno [klicken]]
<br><br>
[[Datei:PongGameUML.png|600px]]<br>
[Abb. 2: UML]


== '''Vorab wichtig zu wissen!''' ==
==Benötigte Materiallien==
{| class="wikitable"
|+ style = "text-align: left"| Tabelle 1: Materialliste
|-


'''Arduino'''
! Nr. !! Anz.    !! Beschreibung !! Bild
* Der Arduino besitzt unterschiedliche [[Arduino_UNO:_Board_Anatomie | Schnittstellen]], weil der Arduino ein digitaler Mikrocontroller ist, kann er nur 5 Volt ausgeben oder annehmen.
|-
* Bei einer konstanten 5 Volt Spannung, ist die LED immer gleich hell, so ist das Ziel die Spannung zur LED zu reduzieren. Dafür benötigen wir eine PWM Schnittstelle, die Pulsweitenmodulation (PWM) wird in Mikrosekundenbereich ein und ausgeschaltet.
|<big><big>&#9312;</big></big>  || 1 || [[Arduino|Funduino Arduino UNO R3]] ||[[Datei:Arduino Uno R3.jpg|ohne|100px|]]
* Bei einem geringen PWM-Wert ist das 5 Volt Signal kaum noch vorhanden und bei einem hohen PWM-Wert liegt das 5 Volt Signal nahezu durchgehend  am Pin an. Durch die PWM Schnittstelle kann nun die LED unterschiedlich hell leuchten, da die Spannung anpassbar ist.
|-
* Die [[https://de.wikipedia.org/wiki/Pulsdauermodulation PWM]] Schnittstellen sind ganz einfach zu erkennen an diesem Zeichen (~)
|<big><big>&#9313;</big></big>  || 1 || Typ 2 ||[[Datei:Arduino_Kabel.png|ohne|100px|]]
 
|-
'''Steckbrett'''
|<big><big>&#9314;</big></big>  || 14+ || Jumperkabel, männlich/männlich||[[Datei:R19-F-2-2.jpg|ohne|100px|]]
* Erklärung zum arbeiten mit einem Steckbrett [[Steckbrett | klicken!]]
|-
|<big><big>&#9315;</big></big>  || 1 || Steckbrett ||[[Datei:Steckbrett1.png|ohne|100px|]]
|-
|<big><big>&#9316;</big></big>  || 4 || Taster||[[Datei:R12-KT-6.jpg|ohne|100px|]]
|-
|<big><big>&#9317;</big></big>  || 1 || 0.96 I2C OLED Display||[[Datei:OLED 0.96.png|ohne|100px|]]
|}


'''OLED Display'''<br>
== Vorab wichtig zu wissen!==
Das Display verfügt über vier Pins:
[[Datei:OLED 0.96.png|thumb|rigth|200px|Abb. 3: OLED Display]]
* '''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.


== '''Benötigte Materiallien''' ==
===OLED Display:===
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.


{| class="wikitable"
{| class="wikitable"
|+ style = "text-align: left"|
|+ style = "text-align: left"| Tabelle 2: OLED Display Pins
|-
|-
! Nr. !! Anz.    !! Beschreibung !! Link !! !! Pos. !! Anz.    !! Beschreibung !!Link!!
| '''VCC'''  || Pin für die Spannungsversorgung, anzuschließen an den 5V Pin des Mikrocontrollers
|-
|-
|<big><big>&#9312;</big></big>  || 1 || [[Arduino|Funduino Arduino UNO R3]] ||[https://funduinoshop.com/elektronische-module/sonstige/mikrocontroller/funduino-uno-r3-mikrocontroller-arduino-kompatibel  bestellen] ||[[Datei:Arduino Uno R3.jpg|ohne|100px|]]
| '''GND''' || Ground-Pin, anzuschließen an den GND Pin des Mikrocontrollers
|<big><big>&#9313;</big></big>  || viele || Jumper Kabel, männlich/männlich||[https://funduinoshop.com/bauelemente/kabelsysteme/jumper-kabel/40-stueck-breadboardkabel-maennlich/maennlich-20cm bestellen]||[[Datei:R19-F-2-2.jpg|ohne|100px|]]
|-
|-
| '''SDA ''' || Überträgt Daten oder Adressen
|-
|-
|<big><big>&#9314;</big></big>  || 1 || [[Steckbrett]] || [https://funduinoshop.com/bauelemente/steckbretter-und-platinen/steckbretter/breadboard-steckbrett-mit-830-kontakten  bestellen]||[[Datei:R12-A-9-1.jpg|ohne|100px|]]
| '''SCL''' || Überträgt den Takt
|<big><big>&#9316;</big></big> || 2 || Taster|| [https://funduinoshop.com/bauelemente/taster-und-schalter/taster/taster-mit-farbigem-knopf-12-12-6mm/12-12-9mm bestellen]||[[Datei:R12-KT-6.jpg|ohne|100px|]]
|}
 
== Aufbau Schaltung ==
[[Datei:Schaltung_Pong.png|500px|thumb|right|Abb.4 Schaltung Pong Spiel]]
In Abbildung 4 wird die Schaltung für das Projekt "Arduino Pong Spiel" dargestellt.<br>
Bevor mit der Programmierung begonnen werden kann, muss die Schaltung des Projekts aufgebaut werden.
 
==Programmierung==
Es ist wichtig, die [[Programmierrichtlinien Einsteiger|['''Programmierrichtlinien''']]] beim Programmieren einzuhalten.<br><br>
Wenn Sie Fragen zur Programmierung haben, finden Sie die Antworten in den [https://wiki.hshl.de/wiki/index.php/Kategorie:Arduino:_Projekt_Grundkenntnisse ['''Grundkenntnissen''']].
<br>
----
=== Bibliotheken einfügen===
Downloaden Sie die Bibliotheken für das OLED Display[https://github.com/adafruit/Adafruit_SSD1306 ''' [SSD10306]'''] und [https://github.com/adafruit/Adafruit-GFX-Library '''[GFX]'''].<br>
 
'''Benötigt wird: '''
# Kommunikation zum I2C/TWI Gerät: <code>'''Wire.h'''</code>
# Kommunikation mit dem SPI Gerät:  <code>'''SPI.h'''</code>
# Adafruit GFX Grafik: <code>'''Adafruit_GFX.h'''</code>
# 128x64 and 128x32 OLEDs Displays: <code>'''Adafruit_SSD1306.h'''</code>
 
['''Quelltext 1: ''' <code>Pong.ino</code>]
{| role="presentation" class="wikitable mw-collapsible mw-collapsed"
| <strong>Lösung &thinsp;</strong>
|-
|-
|
<syntaxhighlight lang="C" style="border: none; background-color: #EFF1C1; font-size:small">
// Benötigte Bibliotheken
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
</syntaxhighlight>
|}
----
=== Initialisierung Arduino===
'''1. Taster initialisieren'''<br>
Zuerst müssen Sie allen vier Tastern einen Pin am Arduino zugewiesen werden. Diese können Sie beliebig an den digitalen Schnittstellen anschließen.<br>
Danach werden die Pins mit [https://wiki.hshl.de/wiki/index.php/Grundkenntnisse_Programmierung_(Pulsierende_LED)#pinMode() '''<code>pinMode();</code>'''] und [https://wiki.hshl.de/wiki/index.php/Grundkenntnisse_Programmierung_(Arduino_LED_W%C3%BCrfel)#digitalWrite() '''<code>digitalWrite();'''</code>] initialisiert.
['''Quelltext 2: ''' <code>Pong.ino</code>]
{| role="presentation" class="wikitable mw-collapsible mw-collapsed"
| <strong>Lösung &thinsp;</strong>
|-
|-
|<big><big>&#9317;</big></big>  || 1 || 0.96 I2C OLED Display|| [https://funduinoshop.com/elektronische-module/displays/oled/oled-0.96-128x64-gvss-i2c bestellen]||[[Datei:OLED 0.96.png|ohne|100px|]]
|      
<syntaxhighlight lang="C" style="border: none; background-color: #EFF1C1; font-size:small">
/* Taster PINS */
const char UP_BUTTON = 2;
const char DOWN_BUTTON = 3;
const char UP_BUTTON_TWO = 4;
const char DOWN_BUTTON_TWO = 5;
 
void setup()
{
/* Taster initialisieren */
pinMode(UP_BUTTON, INPUT);
pinMode(DOWN_BUTTON, INPUT);               
digitalWrite(UP_BUTTON, HIGH);
digitalWrite(DOWN_BUTTON, HIGH);
   
/* Taster zwei */
pinMode(UP_BUTTON_TWO, INPUT);
pinMode(DOWN_BUTTON_TWO, INPUT);               
digitalWrite(UP_BUTTON_TWO, HIGH);
digitalWrite(DOWN_BUTTON_TWO, HIGH);
 
void loop()
{
 
}
</syntaxhighlight>
|}
|}
[[Datei:PongSchaltung.png|350px|thumb|right|Abb.3 Schaltung]]


== '''Aufbau Schaltung''' ==
'''2. OLED Display initialisieren''' <br>
Nutzen Sie die [https://wiki.hshl.de/wiki/index.php/Grundkenntnisse_Programmierung_(Arduino_Pong_Spiel)#OLED_Display <code>'''Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);'''</code>] Funktion.


* Auf dem Bild (Abb.3 Schaltung) wird dargestellt, wie die Schaltung für das Projekt "Arduino Pong Spiel" aufgebaut werden kann.
['''Quelltext 3: ''' <code>Pong.ino</code>]
{| role="presentation" class="wikitable mw-collapsible mw-collapsed"
| <strong>Lösung &thinsp;</strong>
|-
|     
<syntaxhighlight lang="C" style="border: none; background-color: #EFF1C1; font-size:small">
/* Deklaration Display, Verbindung zum I2C (SDA, SCL pins) */
const char OLED_RESET = 0; // Reset Pin
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
</syntaxhighlight>
|}


== '''Programmierung''' ==
'''3. Variablen initialisieren''' <br>
Auch können vorab Variablen bestimmt werden, die für die Programmierung benötigt werden.<br>
* Die '''Größe des Displays''' und die '''Ball Rate'''<br>
* Zwei Variablen für eine '''Punkteanzeige'''
* BALL_RATE ist die Rate in Millisekunden, mit der der Ball aktualisiert werden soll.
** Höhere Zahl: langsamerer Ball
** Niedrigere Zahl: schnellerer Ball


<big>'''Schritt 1'''</big>
['''Quelltext 4: ''' <code>Pong.ino</code>]
* Erstellen der ersten '''Arduino Datei''' ([https://wiki.hshl.de/wiki/index.php/Erste_Schritte_mit_der_Arduino_IDE Link zum Tutorial]).
{| role="presentation" class="wikitable mw-collapsible mw-collapsed"
| <strong>Lösung &thinsp;</strong>
|-
|     
<syntaxhighlight lang="C" style="border: none; background-color: #EFF1C1; font-size:small">
const unsigned char BALL_RATE = 16;         
const unsigned char PADDLE_HEIGHT = 25;


<big>'''Schritt 2'''</big>
const char SCREEN_WIDTH = 128;      // OLED Display Breite
* Grundkenntnisse vom Projekt '''"Pulsierende LED"''' verstanden haben. ([[Grundkenntnisse Programmierung (Pulsierende LED) |Link]]).
const char SCREEN_HEIGHT = 64;    // OLED Display Höhe
* Grundkenntnisse vom Projekt '''"Arduino LED Würfel"''' verstanden haben([[Grundkenntnisse Programmierung (Arduino LED Würfel) |Link]]).
* Grundkenntnisse für das Projekt '''"Ultraschallsensor Sicherheitssystem mit Buzzer"''' verstehen([[Grundkenntnisse Programmierung (USS mit Buzzer) |Link zu den Grundkenntnissen]]).


<big>'''Schritt 3'''</big>
unsigned int playerOne = 0, playerTwo = 0;
* Nachdem die Schritte 1 und 2 abgeschlossen sind, kann mit der Programmierung des Projektes gestartet werden.
</syntaxhighlight>
<br>
|}
'''1)''' '''Initialisierung''' <br>
 
Nachdem das Projekt aufgebaut ist, kann mit der Programmierung begonnen werden.<br>
'''4. Position vom Ball, Paddle und Spieler auf dem Display festlegen''' <br>
Zuerst müssen die verwendeten Schnittstellen am Arduino initaliersiert werden. <br>
* Benötigte Postionen sind: '''Ball, Spieler 1 (playerOne) und Spieler 2 (playerTwo)'''.<br>
Hierfür wird zusätzlich eine neue Methode verwendet, siehe #define Grundkenntnisse.<br>
* Benötigt wird eine Update-Variable, um den Ball zu bewegen.<br>
'''Tipp:''' Initalisiert werden müssen, LEDs, Buzzer, Ultraschallsensor und die internen Timer und Variablen.
* Dieser Werte können nach Geschmack angepasst werden.


['''Quelltext 5: ''' <code>Pong.ino</code>]
{| role="presentation" class="wikitable mw-collapsible mw-collapsed"
{| role="presentation" class="wikitable mw-collapsible mw-collapsed"
| <strong>Lösung &thinsp;</strong>
| <strong>Lösung &thinsp;</strong>
|-
|-
|
|      
<syntaxhighlight lang="c" style="background-color: #EFF1C1; font-size:larger">
<syntaxhighlight lang="C" style="border: none; background-color: #EFF1C1; font-size:small">
#define trigPin 7
unsigned char ballX = 64, ballY = 32;
#define echoPin 6
unsigned char ballDir_x = 1, ballDir_y = 1;
#define LEDlampRed 9
 
#define LEDlampYellow 10
const unsigned char PLAYER_TWO_X = 12;
#define LEDlampGreen 11
unsigned char playerTwo_y = 16;
#define soundbuzzer 3
 
int sound = 500;                       // Frequenz von 500 Hertz
const unsigned char PLAYER_ONE_X = 115;
long durationindigit, distanceincm;     //Später benötigt   
unsigned char playerOne_y = 16;
 
unsigned long ballUpdate;
 
</syntaxhighlight>
|}
----
 
=== Display hochfahren===
Um später zu sehen, wo Sie welche Objekte platziert hat, muss das Display hochgefahren werden.<br>
Zusätzlich wird beim Start vom Display ein Timer gesetzt, dieser wird für die Bewegung vom Ball benötigt.<br>
'''Benötigt wird: ''' [https://wiki.hshl.de/wiki/index.php/Grundkenntnisse_Programmierung_(Arduino_Pong_Spiel)#OLED_Display <code>'''display.display();'''</code>] und [https://wiki.hshl.de/wiki/index.php/Grundkenntnisse_Programmierung_(Arduino_Pong_Spiel)#millis()<code>'''mills();'''</code>] zum Zeitauslesen.   
 
['''Quelltext 6: ''' <code>Pong.ino</code>]
{| role="presentation" class="wikitable mw-collapsible mw-collapsed"
| <strong>Lösung Code &thinsp;</strong>
|-
|     
<syntaxhighlight lang="C" style="border: none; background-color: #EFF1C1; font-size:small">
void setup()  
void setup()  
{
{
Später
Serial.begin(9600);
}
 
void loop()  
/* Hochfahren vom Display */
{
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // Starte das Display       
Später
display.display();                    // Zeigt das Startbild vom Arduino an
unsigned long start = millis();      // Anzahl von Ms zurück, seit Arduino-Board das aktuelle Programm gestartet hat
delay(1000);
display.clearDisplay();            // Löscht das Bild
 
/* Ball Timer zuweisen*/
ballUpdate = millis();
delay(1000);
}
}
</syntaxhighlight>
</syntaxhighlight>
|}
|}
'''2)''' '''pinMode()'''<br>
 
Nachdem Initialisieren folgt das festlegen der pinMode() Funktion für die OUTPUTS und INPUTS.<br>
''' Display Spielname anzeigen''' <br>
Hierfür wird die Funktion <code> pinMode(NAME,OUTPUT); </code> oder <code> pinMode(NAME,INPUT); </code> benötigt.<br>
Als optionale Zusatzaufgabe können Sie den Namen '''Pong Spiel''' auf dem Display anzeigen lassen.<br>
 
'''Tipp: ''' Hierfür werden die <code>'''display.set();'''</code> und <code>'''display.println'''();</code> Funktionen benötigt.
 
['''Quelltext 7: ''' <code>Pong.ino</code>]
{| role="presentation" class="wikitable mw-collapsible mw-collapsed"
| <strong>Lösung &thinsp;</strong>
|-
|     
<syntaxhighlight lang="C" style="border: none; background-color: #EFF1C1; font-size:small">
/* Pong Spiel Namen anzeigen */
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(5, 25);
  display.println("Pong Spiel");
  display.display();
  delay(1000);
  display.clearDisplay();
</syntaxhighlight>
|}
----
 
=== Display Punkteanzeige===
Um die Punktanzeige ins Spiel mit einzubringen, werden zwei Methoden benötigt.<br>
* Die erste Methode soll die Zahlen auf dem Display anzeigen.<br>
* Die zweite Methode soll die erstellen Zahlen wieder löschen, um das nächste Ergebnis korrekt anzuzeigen.<br>
 
'''Tipp: ''' Hierfür werden die <code>'''display.set();'''</code> und <code>'''display.println();'''</code> Funktionen benötigt.
 
['''Quelltext 8: ''' <code>Pong.ino</code>]
{| role="presentation" class="wikitable mw-collapsible mw-collapsed"
{| role="presentation" class="wikitable mw-collapsible mw-collapsed"
| <strong>Lösung &thinsp;</strong>
| <strong>Lösung &thinsp;</strong>
|-
|-
|       
|       
<syntaxhighlight lang="C" style="border: none; background-color: #EFF1C1; font-size:14px">
<syntaxhighlight lang="C" style="border: none; background-color: #EFF1C1; font-size:small">
void setup() {
 
  pinMode(trigPin, OUTPUT);       // trigPin ist ein Ausgang
void drawScore()  
  pinMode(echoPin, INPUT);         // echoPin ist ein Eingang
{
  pinMode(LEDlampRed, OUTPUT);
display.setTextSize(2);
  pinMode(LEDlampYellow, OUTPUT);
display.setTextColor(WHITE);
  pinMode(LEDlampGreen, OUTPUT);
display.setCursor(43, 0);
  pinMode(soundbuzzer, OUTPUT);
display.println(playerOne);
 
display.setCursor(73, 0);
display.println(playerTwo);
}
 
/* Punkte zurücksetzten */
void eraseScore()
{
display.setTextSize(2);
display.setTextColor(BLACK);
display.setCursor(43, 0);
display.println(playerOne);
 
display.setCursor(73, 0);
display.println(playerTwo);
}
}
</syntaxhighlight>
</syntaxhighlight>
|}
|}


'''3)''' '''Ultraschallsensor'''<br>
----
Der nächste Schritt soll der Ultraschallsensor eine Ultraschallwelle für eine gewisse Zeit lossenden.<br>
 
Dies lässt sich über den trigerPin und <code>digitalWrite(Name, HIGH);</code> umsetzen.
=== Bewegter Ball===
Damit der Ball sich auf dem Display bewegt, benötigt Sie eine '''Rechenfunktion'''.<br>
 
'''Tipp: ''' Rechnen Sie den X und Y Wert + 1 und erstellen Sie eine neue Variable.
 
['''Quelltext 9: ''' <code>Pong.ino</code>]
{| role="presentation" class="wikitable mw-collapsible mw-collapsed"
{| role="presentation" class="wikitable mw-collapsible mw-collapsed"
| <strong>Lösung &thinsp;</strong>
| <strong>Lösung &thinsp;</strong>
|-
|-
|      
|
<syntaxhighlight lang="C" style="border: none; background-color: #EFF1C1; font-size:14px">
<syntaxhighlight lang="C" style="border: none; background-color: #EFF1C1; font-size:small">
void loop() {
void loop() {
    
   unsigned long time = millis();              // Zeit-Variable
digitalWrite(trigPin, LOW); //Hier nimmt man die Spannung für kurze Zeit vom Trigger-Pin, damit man später beim senden des Trigger-Signals ein rauschfreies Signal hat.
 
delay(5); //Dauer: 5 Millisekunden
/* Neue Ballposition */
digitalWrite(trigPin, HIGH); //Jetzt sendet man eine Ultraschallwelle los.
if (time > Ball_update) {
delay(10); //Dieser „Ton“ erklingt für 10 Millisekunden.
  unsigned char New_x = Ball_x + Ball_dir_x;              // (x+1)
digitalWrite(trigPin, LOW);//Dann wird der „Ton“ abgeschaltet.
  unsigned char New_y = Ball_y + Ball_dir_y;               // (y+1)
}
}
</syntaxhighlight>
|}
 
'''1. Wände erkennen''' <br>
Damit der Ball wie gewünscht von den Wänden abprallt, müssen die Wände bei Berührung mit einer [https://wiki.hshl.de/wiki/index.php/Grundkenntnisse_Programmierung_(Pulsierende_LED)#if-Bedingung <code>'''if-Bedingung()'''</code>] abgefragt werden.<br>
* Wenn der Ball auf eine Wand trifft, muss die Richtung vom Ball geändert werden.<br>
* Zusätzlich soll der Spieler einen Punkt bekommen, wenn die linke oder rechte Wand berührt wurde.<br>
 
'''Tipp: ''' Wenn die X oder Y Position von der Wand erreicht wurde, negieren Sie den Addierer.
 
['''Quelltext 10: ''' <code>Pong.ino</code>]
{| role="presentation" class="wikitable mw-collapsible mw-collapsed"
| <strong>Lösung &thinsp;</strong>
|-
|
<syntaxhighlight lang="C" style="border: none; background-color: #EFF1C1; font-size:small">
/* Checkt ob die vertikalen Wände berührt werden */
  if (New_x == 0)  // Wand links
  {                       
    ballDir_x = -ballDir_x;            // Wechselt die Richtung
    New_x += ballDir_x + ballDir_x;
    eraseScore();                        // Punkt für Spieler
    playerOne += 1;
    drawScore();
    New_x = 64;                          // Ball Reset
    New_y = 32;
  }
 
  if (New_x == 127)   // Wand rechts
  {                   
      ballDir_x = -ballDir_x;           // Wechselt die Richtung
      New_x += ballDir_x + ballDir_x;
      eraseScore();                       // Punkt für Spieler 2
      playerTwo += 1;
      drawScore();
      New_x = 64;                          // Ball Reset
      New_y = 32;
    }
 
// Checkt ob die horizontalen Wände berührt werden
  if (New_y == 0 || New_y == 63)  
  {
    ballDir_y = -ballDir_y;           // Wechselt die Richtung
    New_y += ballDir_y + ballDir_y;
  }
</syntaxhighlight>
</syntaxhighlight>
|}
|}
'''3.1)''' '''Entfernung und Dauer'''<br>
 
Nun muss noch die Entfernung und die Dauer von der Ultraschallwelle bestimmt werden.<br>
'''2. Paddel erkennen''' <br>
Die Dauer wird mit der Funktion <code>pulseIn(Name,HIGH);</code> bestimmt.<br>
Auch muss der Ball, wenn er den Schläger berührt, seine Richtung ändern.<br>
Um die Entfernung zu messen benötigt man eine Rechnung die wie folgt ablaufen soll.<br>
 
Zurechnen ist die Strecke von einem Weg mal die Schallgeschwindigkeit = 0.03432.
'''Tipp: ''' Die Position von den Paddeln muss kleiner sein als die Position vom Ball.
 
['''Quelltext 11: ''' <code>Pong.ino</code>]
{| role="presentation" class="wikitable mw-collapsible mw-collapsed"
{| role="presentation" class="wikitable mw-collapsible mw-collapsed"
| <strong>Lösung &thinsp;</strong>
| <strong>Lösung &thinsp;</strong>
|-
|-
|      
|
<syntaxhighlight lang="C" style="border: none; background-color: #EFF1C1; font-size:14px">
<syntaxhighlight lang="C" style="border: none; background-color: #EFF1C1; font-size:small">
dauer = pulseIn(echoPin, HIGH); //Mit dem Befehl „pulseIn“ zählt der Mikrokontroller die Zeit in Mikrosekunden, bis der Schall zum Ultraschallsensor zurückkehrt.
// Checkt, ob der Spieler 1 Paddel getroffen wurde
entfernung = (dauer/2) * 0.03432;  
  if (New_x == PLAYER_ONE_X && New_y >= playerOne_y && New_y <= playerOne_y + PADDLE_HEIGHT)  
//Nun berechnet man die Entfernung in Zentimetern.
  {
//Man teilt zunächst die Zeit durch zwei (Weil man ja nur eine Strecke berechnen möchte und nicht die Strecke hin- und zurück).
    ballDir_x = -ballDir_x;
//Den Wert multipliziert man mit der Schallgeschwindigkeit in der Einheit Zentimeter/Mikrosekunde und erhält dann den Wert in Zentimetern.
    New_x += ballDir_x + ballDir_x;
  }
 
// Checkt, ob der Spieler 2 Paddel getroffen wurde
  if (New_x == PLAYER_TWO_X && New_y >= playerTwo_y && New_y <= playerTwo_y + PADDLE_HEIGHT) {
    ballDir_x = -ballDir_x;
    New_x += ballDir_x + ballDir_x;
  }
</syntaxhighlight>
</syntaxhighlight>
|}
|}
'''4)''' '''Serieller Monitor''' <br>
Um später die Werte vom Sensor im Programm ansehen zu können, wird der Seriell Monitor benötigt.<br>
Dieser wird im void setup() mit der Funktion: <code>Serial.begin (9600); </code> initalisiert.<br>


'''5)''' '''If-Verzweigung für LEDs und Buzzer''' <br>
'''3. Neue Ballposition anzeigen''' <br>
Im letzten Schritt soll eine If-Verzweigung erstellt werden, die dafür sorgt das ab einer bestimmten Entfernung die LEDs leuchten.<br>
Nun kann sich der Ball bewegen, muss aber noch auf dem Display als Pixel angezeigt und die alten Pixel wieder gelöscht werden.<br>
Zusätzlich soll bei der Roten LED der Buzzer einen Ton abspielen.<br>
Außerdem müssen die neuen Variablen übertragen werden auf die alten, um weitere Abläufe zu ermöglichen.<br>
Tipp: digitalWrite(Name, HIGH/LOW); sound = Wert;  tone(); noTone();


'''Tipp: '''Nutze <code>'''display.drawPixel(Name, Name, BLACK/WHITE);'''</code>.
['''Quelltext 12: ''' <code>Pong.ino</code>]
{| role="presentation" class="wikitable mw-collapsible mw-collapsed"
{| role="presentation" class="wikitable mw-collapsible mw-collapsed"
| <strong>Lösung &thinsp;</strong>
| <strong>Lösung &thinsp;</strong>
|-
|-
|      
|
<syntaxhighlight lang="C" style="border: none; background-color: #EFF1C1; font-size:14px">
<syntaxhighlight lang="C" style="border: none; background-color: #EFF1C1; font-size:small">
void loop() {
display.drawPixel(ballX, ballY, BLACK);
  if (entfernung < 15) {                            // Trifft zu wenn: entfernung kleiner als 15 ist!
    display.drawPixel(New_x, New_y, WHITE);
    digitalWrite(LEDlampGreen, HIGH);               // LED Grün geht an
    ballX = New_x;
    ballY = New_y;
 
    ballUpdate += BALL_RATE;
    update = true;              // true ~ display.display();
   }
   }
  else {
</syntaxhighlight>
    digitalWrite(LEDlampGreen, LOW);               // Sonst ist die LED Grün aus!
|}
  }
 
  if (entfernung < 10) {
-----
    digitalWrite(LEDlampYellow, HIGH);
 
  }
=== Boolean Taster===
  else {
Um die Taster abzufragen und falsche Eingaben zu überprüfen, wird mit einem [https://wiki.hshl.de/wiki/index.php/Grundkenntnisse_Programmierung_(Arduino_Pong_Spiel)#bool <code>'''bool'''</code>] programmiert.<br>
    digitalWrite(LEDlampYellow,LOW);
 
  }
'''Tipp: '''
  if (entfernung < 5) {
# Neue Variablen für die Taster mit <code>'''bool'''</code> initialisieren.
    digitalWrite(LEDlampRed, HIGH);
# Die alten und neuen Variablen auf <code>'''LOW'''</code> zu setzen, um die Taster schalten zu können.
    sound = 1000;
# Wenn die <code>'''bool'''</code> <code>'''Variable = true'''</code> ist, soll das Display mit <code>'''display.display();'''</code> aktualisiert werden.
 
['''Quelltext 13: ''' <code>Pong.ino</code>]
{| role="presentation" class="wikitable mw-collapsible mw-collapsed"
| <strong>Lösung &thinsp;</strong>
|-
|
<syntaxhighlight lang="C" style="border: none; background-color: #EFF1C1; font-size:small">
bool update = false;                          // Ein bool enthält einen von zwei Werten, true oder false
unsigned long time = millis();              // Zeit-Variable
 
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);
DOWN_STATE_TWO |= (digitalRead(DOWN_BUTTON_TWO) == LOW);
 
if (update)                      // Wenn Variable = true wird display.display(); ausgeführt
display.display();
}
</syntaxhighlight>
|}
 
----
 
=== Paddel Spieler===
Der letzte Schritt ist, die Schläger mit den Tastern steuerbar zu machen.<br>
Diese dürfen aber nicht aus dem Display gelangen.<br>
 
'''Tipp: '''<br>
# Der Ablauf ist ähnlich wie beim Ball, nur wird die if-Bedingung von den Tastern betätigt.
# Zusätzlich müssen noch die Schläger auf dem Display mit der Funktion <br> <code>'''display.drawFastVLine(PLAYER_ONE_X, playerOne_y, PADDLE_HEIGHT, BLACK);'''</code> angezeigt werden.
 
['''Quelltext 14: ''' <code>Pong.ino</code>]
{| role="presentation" class="wikitable mw-collapsible mw-collapsed"
| <strong>Lösung &thinsp;</strong>
|-
|
<syntaxhighlight lang="C" style="border: none; background-color: #EFF1C1; font-size:small">
/* Spieler 1 Paddel */
  display.drawFastVLine(PLAYER_ONE_X, playerOne_y, PADDLE_HEIGHT, BLACK);
  if (UP_STATE)
  {
  playerOne_y -= 1;
   }
   }
   else {
   if (DOWN_STATE)
     digitalWrite(LEDlampRed,LOW);
  {
     playerOne_y += 1;
   }
   }
  UP_STATE = DOWN_STATE = false;
    
    
  if (entfernung > 5 || entfernung <= 0){
  if (playerOne_y < 1) playerOne_y = 1;                                    // Um nicht aus dem Bildschirm zu gelangen
    Serial.println("Außerhalb der Range");
  if (playerOne_y + PADDLE_HEIGHT > 63) playerOne_y = 63 - PADDLE_HEIGHT;
    noTone(soundbuzzer);
  display.drawFastVLine(PLAYER_ONE_X, playerOne_y, PADDLE_HEIGHT, WHITE);
 
  update = true;
 
/* Spieler 2 Paddel */
  display.drawFastVLine(PLAYER_TWO_X, playerTwo_y, PADDLE_HEIGHT, BLACK);
  if (UP_STATE_TWO)  
  {
    playerTwo_y -= 1;                       // Paddle 1 nach unten
   }
   }
   else {
   if (DOWN_STATE_TWO)  
    Serial.print(entfernung);
  {
    Serial.println(" cm");
     playerTwo_y += 1;                     // Paddle 1 nach oben
     tone(soundbuzzer, sound);
   }
   }
  UP_STATE_TWO = DOWN_STATE_TWO = false;
    
    
   delay(300);
   if (playerTwo_y < 1) playerTwo_y = 1;                                        // Um nicht aus dem Bildschirm zugelangen
  if (playerTwo_y + PADDLE_HEIGHT > 63) playerTwo_y = 63 - PADDLE_HEIGHT;
  display.drawFastVLine(PLAYER_TWO_X, playerTwo_y, PADDLE_HEIGHT, WHITE);
 
  if (update)                    //hierhin verschieben
  display.display();
}
}
</syntaxhighlight>
</syntaxhighlight>
|}
|}
<big>'''Schritt 4'''</big>
* Nach dem beenden von Schritt 3, kann nun das Ergebnis mit der Musterlösung verglichen werden.


== '''Musterlösung''' ==
== Musterlösung ==  
 
Quelle: https://projecthub.arduino.cc/Krepak/ultrasonic-security-system-a6ea3a
{| role="presentation" class="wikitable mw-collapsible mw-collapsed"
{| role="presentation" class="wikitable mw-collapsible mw-collapsed"
| <strong>Lösung Code &thinsp;</strong>
| <strong>Lösung Code &thinsp;</strong>
|-
|-
|       
|       
<syntaxhighlight lang="C" style="border: none; background-color: #EFF1C1; font-size:14px">
<syntaxhighlight lang="C" style="border: none; background-color: #EFF1C1; font-size:small">
#define trigPin 7
/* Benötigte Bibliotheken */
#define echoPin 6
#include <SPI.h>
#define LEDlampRed 9
#include <Wire.h>
#define LEDlampYellow 10
#include <Adafruit_GFX.h>
#define LEDlampGreen 11
#include <Adafruit_SSD1306.h>
#define soundbuzzer 3
 
int sound = 500;  // Frequenz von 500 Hertz
/* Taster PINS */
long dauer, entfernung;
const char UP_BUTTON = 2;
const char DOWN_BUTTON = 3;
const char UP_BUTTON_TWO = 4;
const char DOWN_BUTTON_TWO = 5;
 
/* Variablen */
const unsigned char BALL_RATE = 16;         
const unsigned char PADDLE_HEIGHT = 25;
 
const char SCREEN_WIDTH = 128;      // OLED Display Breite
const char SCREEN_HEIGHT = 64;    // OLED Display Höhe
 
unsigned int playerOne = 0, playerTwo = 0;
 
/* Deklaration Display, verbindung zum I2C (SDA, SCL pins) */
const char OLED_RESET = 0; // Reset pin
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
 
 
/* Position vom Ball, Paddle und Spieler auf dem Display */
 
unsigned char ballX = 64, ballY = 32;
unsigned char ballDir_x = 1, ballDir_y = 1;
 
const unsigned char PLAYER_TWO_X = 12;
unsigned char playerTwo_y = 16;
 
const unsigned char PLAYER_ONE_X = 115;
unsigned char playerOne_y = 16;
 
unsigned long ballUpdate;
 
void setup()
{
Serial.begin(9600);
 
  /* Hochfahren vom Display */
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // Starte das Display
display.display();                    // Zeigt das Startbild vom Arduino an
unsigned long start = millis();      // Anzahl von Ms zurück, seit Arduino-Board das aktuelle Programm gestartet hat
delay(1000);
display.clearDisplay();            // Löscht das Bild
 
/* Pong Spiel Namen anzeigen */
display.setTextSize(2);
display.setTextColor(WHITE);
display.setCursor(5, 25);
display.println("Pong Spiel");
display.display();
delay(1000);
display.clearDisplay();
 
/* Ball Timer zuweisen*/
ballUpdate = millis();
delay(1000);
 
/* Taster Initialisieren */
pinMode(UP_BUTTON, INPUT);      // Taster als INPUT festlegen
pinMode(DOWN_BUTTON, INPUT);
digitalWrite(UP_BUTTON, HIGH);      // Taster anschalten
digitalWrite(DOWN_BUTTON, HIGH);


void setup() {
/* Taster zwei */
  Serial.begin (9600);            //Serielle kommunikation starten, damit man sich später die Werte am serial monitor ansehen kann.
pinMode(UP_BUTTON_TWO, INPUT);
  pinMode(trigPin, OUTPUT);       // trigPin ist ein Ausgang
pinMode(DOWN_BUTTON_TWO, INPUT);
  pinMode(echoPin, INPUT);        // echoPin ist ein Eingang
digitalWrite(UP_BUTTON_TWO, HIGH);
  pinMode(LEDlampRed, OUTPUT);
digitalWrite(DOWN_BUTTON_TWO, HIGH);
  pinMode(LEDlampYellow, OUTPUT);
  pinMode(LEDlampGreen, OUTPUT);
  pinMode(soundbuzzer, OUTPUT);
}
}
void loop() {
 
digitalWrite(trigPin, LOW); //Hier nimmt man die Spannung für kurze Zeit vom Trigger-Pin, damit man später beim senden des Trigger-Signals ein rauschfreies Signal hat.
delay(5); //Dauer: 5 Millisekunden
digitalWrite(trigPin, HIGH); //Jetzt sendet man eine Ultraschallwelle los.
delay(10); //Dieser „Ton“ erklingt für 10 Millisekunden.
digitalWrite(trigPin, LOW);//Dann wird der „Ton“ abgeschaltet.
dauer = pulseIn(echoPin, HIGH); //Mit dem Befehl „pulseIn“ zählt der Mikrokontroller die Zeit in Mikrosekunden, bis der Schall zum Ultraschallsensor zurückkehrt.
entfernung = (dauer/2) * 0.03432;
//Nun berechnet man die Entfernung in Zentimetern.
//Man teilt zunächst die Zeit durch zwei (Weil man ja nur eine Strecke berechnen möchte und nicht die Strecke hin- und zurück).
//Den Wert multipliziert man mit der Schallgeschwindigkeit in der Einheit Zentimeter/Mikrosekunde und erhält dann den Wert in Zentimetern.


   
/* Punkteanzeige */
   if (entfernung < 15) {                             // Trifft zu wenn: entfernung kleiner als 15 ist!
void drawScore()
     digitalWrite(LEDlampGreen, HIGH);               // LED Grün geht an
{
display.setTextSize(2);
display.setTextColor(WHITE);
display.setCursor(43, 0);
display.println(playerOne);
 
display.setCursor(73, 0);
display.println(playerTwo);
}
 
/* Punkte zurücksetzten */
void eraseScore()
{
display.setTextSize(2);
display.setTextColor(BLACK);
display.setCursor(43, 0);
display.println(playerOne);
 
display.setCursor(73, 0);
display.println(playerTwo);
}
 
void loop()
{
drawScore();
 
bool update = false;                          // Ein bool enthält einen von zwei Werten, true oder false
unsigned long time = millis();              // Zeit-Variable
 
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);
DOWN_STATE_TWO |= (digitalRead(DOWN_BUTTON_TWO) == LOW);
 
/* Neue Ballposition */
  if (time > ballUpdate)
  {
  unsigned char New_x = ballX + ballDir_x;              // (x+1)
  unsigned char New_y = ballY + ballDir_y;              // (y+1)
 
/* Checkt ob die vertikalen Wände berührt werden */
  if (New_x == 0) // Wand links
  {                       
    ballDir_x = -ballDir_x;            // Wechselt die Richtung
    New_x += ballDir_x + ballDir_x;
    eraseScore();                        // Punkt für Spieler
    playerOne += 1;
    drawScore();
    New_x = 64;                          // Ball Reset
    New_y = 32;
  }
 
  if (New_x == 127)   // Wand rechts
  {                   
      ballDir_x = -ballDir_x;            // Wechselt die Richtung
      New_x += ballDir_x + ballDir_x;
      eraseScore();                        // Punkt für Spieler 2
      playerTwo += 1;
      drawScore();
      New_x = 64;                          // Ball Reset
      New_y = 32;
    }
 
// Checkt ob die horizontalen Wände berührt werden
  if (New_y == 0 || New_y == 63)
  {
    ballDir_y = -ballDir_y;          // Wechselt die Richtung
    New_y += ballDir_y + ballDir_y;
  }
 
// Checkt, ob der Spieler 1 Paddel getroffen wurde
  if (New_x == PLAYER_ONE_X && New_y >= playerOne_y && New_y <= playerOne_y + PADDLE_HEIGHT)  
  {
    ballDir_x = -ballDir_x;
    New_x += ballDir_x + ballDir_x;
  }
 
// Checkt, ob der Spieler 2 Paddel getroffen wurde
  if (New_x == PLAYER_TWO_X && New_y >= playerTwo_y && New_y <= playerTwo_y + PADDLE_HEIGHT) {
    ballDir_x = -ballDir_x;
    New_x += ballDir_x + ballDir_x;
  }
    display.drawPixel(ballX, ballY, BLACK);
     display.drawPixel(New_x, New_y, WHITE);
    ballX = New_x;
    ballY = New_y;
 
    ballUpdate += BALL_RATE;
    update = true;              // true ~ display.display();
   }
   }
   else {
 
    digitalWrite(LEDlampGreen, LOW);               // Sonst ist die LED Grün aus!
/* Spieler 1 Paddel */
   display.drawFastVLine(PLAYER_ONE_X, playerOne_y, PADDLE_HEIGHT, BLACK);
  if (UP_STATE)  
  {
  playerOne_y -= 1;
   }
   }
 
   if (DOWN_STATE)  
   if (entfernung < 10) {
   {
    digitalWrite(LEDlampYellow, HIGH);
     playerOne_y += 1;
  }
  else {
    digitalWrite(LEDlampYellow,LOW);
  }
   if (entfernung < 5) {
     digitalWrite(LEDlampRed, HIGH);
    sound = 1000;
  }
  else {
    digitalWrite(LEDlampRed,LOW);
   }
   }
  UP_STATE = DOWN_STATE = false;
    
    
  if (entfernung > 5 || entfernung <= 0){
  if (playerOne_y < 1) playerOne_y = 1;                                    // Um nicht aus dem Bildschirm zu gelangen
    Serial.println("Außerhalb der Range");
  if (playerOne_y + PADDLE_HEIGHT > 63) playerOne_y = 63 - PADDLE_HEIGHT;
    noTone(soundbuzzer);
  display.drawFastVLine(PLAYER_ONE_X, playerOne_y, PADDLE_HEIGHT, WHITE);
 
  update = true;
 
/* Spieler 2 Paddel */
  display.drawFastVLine(PLAYER_TWO_X, playerTwo_y, PADDLE_HEIGHT, BLACK);
  if (UP_STATE_TWO)  
  {
    playerTwo_y -= 1;                       // Paddle 1 nach unten
   }
   }
   else {
   if (DOWN_STATE_TWO)  
    Serial.print(entfernung);
  {
    Serial.println(" cm");
     playerTwo_y += 1;                     // Paddle 1 nach oben
     tone(soundbuzzer, sound);
   }
   }
  UP_STATE_TWO = DOWN_STATE_TWO = false;
    
    
   delay(300);
   if (playerTwo_y < 1) playerTwo_y = 1;                                        // Um nicht aus dem Bildschirm zugelangen
  if (playerTwo_y + PADDLE_HEIGHT > 63) playerTwo_y = 63 - PADDLE_HEIGHT;
  display.drawFastVLine(PLAYER_TWO_X, playerTwo_y, PADDLE_HEIGHT, WHITE);
 
  if (update)
  display.display();
}
}
</syntaxhighlight>
</syntaxhighlight>
|}
|}
[https://github.com/shveytank/Arduino_Pong_Game Quelle]


{| role="presentation" class="wikitable mw-collapsible mw-collapsed"
<br>
| <strong>Lösung Serieller Monitor &thinsp;</strong>
----
|-
'''→ zurück zum Hauptartikel: [[Konzipierung_und_Evaluierung_von_Arduino-Projekten_verschiedener_Schwierigkeitsgrade_für_die_Lehre | BA: Arduino-Projekte für die Lehre]]'''
[[Datei:SerMonitor.png|800px]]
|}
 
 
→ zurück zum Hauptartikel: [[Konzipierung_und_Evaluierung_von_Arduino-Projekten_verschiedener_Schwierigkeitsgrade_für_die_Lehre | Klicken!]]

Aktuelle Version vom 12. September 2023, 07:10 Uhr

Abb. 1: Pong Spiel

Autor: Justin Frommberger

Aufgabenstellung

Das Ziel dieses Projektes ist, ein 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 zwei Tastern nach oben und unten steuern kann.
  • Wenn die linke oder rechte Wand berührt wird, erhält der Gegner einen Punkt.

⇒ Für den Fall, dass kein Arduino zur Verfügung steht oder Materialien nicht vorhanden sind. Kann dieser webbasierter Arduino Emulator verwendet werden. [klicken]


[Abb. 2: UML]

Benötigte Materiallien

Tabelle 1: Materialliste
Nr. Anz. Beschreibung Bild
1 Funduino Arduino UNO R3
1 Typ 2
14+ Jumperkabel, männlich/männlich
1 Steckbrett
4 Taster
1 0.96 I2C OLED Display

Vorab wichtig zu wissen!

Abb. 3: OLED Display

OLED Display:

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.

Tabelle 2: OLED Display 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 Überträgt Daten oder Adressen
SCL Überträgt den Takt

Aufbau Schaltung

Abb.4 Schaltung Pong Spiel

In Abbildung 4 wird die Schaltung für das Projekt "Arduino Pong Spiel" dargestellt.
Bevor mit der Programmierung begonnen werden kann, muss die Schaltung des Projekts aufgebaut werden.

Programmierung

Es ist wichtig, die [Programmierrichtlinien] beim Programmieren einzuhalten.

Wenn Sie Fragen zur Programmierung haben, finden Sie die Antworten in den [Grundkenntnissen].


Bibliotheken einfügen

Downloaden Sie die Bibliotheken für das OLED Display [SSD10306] und [GFX].

Benötigt wird:

  1. Kommunikation zum I2C/TWI Gerät: Wire.h
  2. Kommunikation mit dem SPI Gerät: SPI.h
  3. Adafruit GFX Grafik: Adafruit_GFX.h
  4. 128x64 and 128x32 OLEDs Displays: Adafruit_SSD1306.h

[Quelltext 1: Pong.ino]


Initialisierung Arduino

1. Taster initialisieren
Zuerst müssen Sie allen vier Tastern einen Pin am Arduino zugewiesen werden. Diese können Sie beliebig an den digitalen Schnittstellen anschließen.
Danach werden die Pins mit pinMode(); und digitalWrite(); initialisiert.

[Quelltext 2: Pong.ino]

2. OLED Display initialisieren
Nutzen Sie die Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); Funktion.

[Quelltext 3: Pong.ino]

3. Variablen initialisieren
Auch können vorab Variablen bestimmt werden, die für die Programmierung benötigt werden.

  • Die Größe des Displays und die Ball Rate
  • Zwei Variablen für eine Punkteanzeige
  • BALL_RATE ist die Rate in Millisekunden, mit der der Ball aktualisiert werden soll.
    • Höhere Zahl: langsamerer Ball
    • Niedrigere Zahl: schnellerer Ball

[Quelltext 4: Pong.ino]

4. Position vom Ball, Paddle und Spieler auf dem Display festlegen

  • Benötigte Postionen sind: Ball, Spieler 1 (playerOne) und Spieler 2 (playerTwo).
  • Benötigt wird eine Update-Variable, um den Ball zu bewegen.
  • Dieser Werte können nach Geschmack angepasst werden.

[Quelltext 5: Pong.ino]


Display hochfahren

Um später zu sehen, wo Sie welche Objekte platziert hat, muss das Display hochgefahren werden.
Zusätzlich wird beim Start vom Display ein Timer gesetzt, dieser wird für die Bewegung vom Ball benötigt.
Benötigt wird: display.display(); und mills(); zum Zeitauslesen.

[Quelltext 6: Pong.ino]

Display Spielname anzeigen
Als optionale Zusatzaufgabe können Sie den Namen Pong Spiel auf dem Display anzeigen lassen.

Tipp: Hierfür werden die display.set(); und display.println(); Funktionen benötigt.

[Quelltext 7: Pong.ino]


Display Punkteanzeige

Um die Punktanzeige ins Spiel mit einzubringen, werden zwei Methoden benötigt.

  • Die erste Methode soll die Zahlen auf dem Display anzeigen.
  • Die zweite Methode soll die erstellen Zahlen wieder löschen, um das nächste Ergebnis korrekt anzuzeigen.

Tipp: Hierfür werden die display.set(); und display.println(); Funktionen benötigt.

[Quelltext 8: Pong.ino]


Bewegter Ball

Damit der Ball sich auf dem Display bewegt, benötigt Sie eine Rechenfunktion.

Tipp: Rechnen Sie den X und Y Wert + 1 und erstellen Sie eine neue Variable.

[Quelltext 9: Pong.ino]

1. Wände erkennen
Damit der Ball wie gewünscht von den Wänden abprallt, müssen die Wände bei Berührung mit einer if-Bedingung() abgefragt werden.

  • Wenn der Ball auf eine Wand trifft, muss die Richtung vom Ball geändert werden.
  • Zusätzlich soll der Spieler einen Punkt bekommen, wenn die linke oder rechte Wand berührt wurde.

Tipp: Wenn die X oder Y Position von der Wand erreicht wurde, negieren Sie den Addierer.

[Quelltext 10: Pong.ino]

2. Paddel erkennen
Auch muss der Ball, wenn er den Schläger berührt, seine Richtung ändern.

Tipp: Die Position von den Paddeln muss kleiner sein als die Position vom Ball.

[Quelltext 11: Pong.ino]

3. Neue Ballposition anzeigen
Nun kann sich der Ball bewegen, muss aber noch auf dem Display als Pixel angezeigt und die alten Pixel wieder gelöscht werden.
Außerdem müssen die neuen Variablen übertragen werden auf die alten, um weitere Abläufe zu ermöglichen.

Tipp: Nutze display.drawPixel(Name, Name, BLACK/WHITE);.

[Quelltext 12: Pong.ino]


Boolean Taster

Um die Taster abzufragen und falsche Eingaben zu überprüfen, wird mit einem bool programmiert.

Tipp:

  1. Neue Variablen für die Taster mit bool initialisieren.
  2. Die alten und neuen Variablen auf LOW zu setzen, um die Taster schalten zu können.
  3. Wenn die bool Variable = true ist, soll das Display mit display.display(); aktualisiert werden.

[Quelltext 13: Pong.ino]


Paddel Spieler

Der letzte Schritt ist, die Schläger mit den Tastern steuerbar zu machen.
Diese dürfen aber nicht aus dem Display gelangen.

Tipp:

  1. Der Ablauf ist ähnlich wie beim Ball, nur wird die if-Bedingung von den Tastern betätigt.
  2. Zusätzlich müssen noch die Schläger auf dem Display mit der Funktion
    display.drawFastVLine(PLAYER_ONE_X, playerOne_y, PADDLE_HEIGHT, BLACK); angezeigt werden.

[Quelltext 14: Pong.ino]

Musterlösung

Quelle



→ zurück zum Hauptartikel: BA: Arduino-Projekte für die Lehre