Arduino Projekt: Pong Spiel: Unterschied zwischen den Versionen

Aus HSHL Mechatronik
Zur Navigation springen Zur Suche springen
 
(214 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt)
Zeile 1: Zeile 1:
[[Kategorie:Arduino: Projekt]]
[[Kategorie:Arduino: Projekt]]
[[Datei:PongGameB.gif|thumb|right|600px|Abb. 1: Pong Spiel]]
[[Datei:PongGame neu.gif|thumb|right|500px|Abb. 1: Pong Spiel]]
'''Autor:''' Justin Frommberger<br/>
'''Autor:''' Justin Frommberger<br>


== '''Aufgabenstellung''' ==
== Aufgabenstellung==
* Das Ziel dieses Projektes ist eigenes Pong spiel umzusetzen.
Das Ziel dieses Projektes ist, ein eigenes Pong-Spiel umzusetzen.
* Ein Punkt (Ball) bewegt sich auf dem Bildschirm hin und her.  
* 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.  
* Jeder der beiden Spieler steuert einen senkrechten Strich (Schläger), den er mit zwei Tastern nach oben und unten steuern kann.  
* Lässt man den „Ball“ am „Schläger“ vorbei und berührt die Wand, erhält der Gegner einen Punkt.
* Wenn die linke oder rechte Wand berührt wird, erhält der Gegner einen Punkt.<br>


== '''Benötigte Software''' ==
⇒ 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]]
*Aktuellste '''Arduino IDE''' mit der Version für ihren PC. [https://www.arduino.cc/en/software/ (Download link)]
<br><br>
*Bibliotheken für das OLED Display: [https://github.com/adafruit/Adafruit_SSD1306 Adafruit_SSD1306] und  [https://github.com/adafruit/Adafruit-GFX-Library Adafruit-GFX-Library] downloaden.
[[Datei:PongGameUML.png|600px]]<br>
** Klicke oben rechts in GitHub auf Code und dann downloade die Zip-Datei.
[Abb. 2: UML]
** Um die Zip-Datei in ihre Arduino Bibliothek einzubinden, folgen diese Schritte: [https://ardutronix.de/anleitung-library-in-arduino-ide-installieren-und-einbinden/ (Link)]


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


! Nr. !! Anz.    !! Beschreibung !! Bild !! Pos. !! Anz.    !! Beschreibung !!Bild
! Nr. !! Anz.    !! Beschreibung !! Bild
|-
|-
|<big><big>&#9312;</big></big>  || 1 || [[Arduino|Funduino Arduino UNO R3]] ||[[Datei:Arduino Uno R3.jpg|ohne|100px|]]
|<big><big>&#9312;</big></big>  || 1 || [[Arduino|Funduino Arduino UNO R3]] ||[[Datei:Arduino Uno R3.jpg|ohne|100px|]]
|<big><big>&#9313;</big></big>  || viele || Jumper Kabel, männlich/männlich||[[Datei:R19-F-2-2.jpg|ohne|100px|]]
|-
|-
|<big><big>&#9313;</big></big>  || 1 || Typ 2 ||[[Datei:Arduino_Kabel.png|ohne|100px|]]
|-
|-
|<big><big>&#9314;</big></big>  || 1 || [[Steckbrett]] ||[[Datei:R12-A-9-1.jpg|ohne|100px|]]
|<big><big>&#9314;</big></big>  || 14+ || Jumperkabel, männlich/männlich||[[Datei:R19-F-2-2.jpg|ohne|100px|]]
|<big><big>&#9315;</big></big>  || 4 || Taster||[[Datei:R12-KT-6.jpg|ohne|100px|]]
|-
|-
|<big><big>&#9315;</big></big>  || 1 || Steckbrett ||[[Datei:Steckbrett1.png|ohne|100px|]]
|-
|-
|<big><big>&#9316;</big></big>  || 1 || 0.96 I2C OLED Display||[[Datei:OLED 0.96.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|]]
|}
|}


== '''Vorab wichtig zu wissen!''' ==
== Vorab wichtig zu wissen!==
[[Datei:OLED 0.96.png|thumb|rigth|250px|Abb. 2: OLED Display]]
[[Datei:OLED 0.96.png|thumb|rigth|200px|Abb. 3: OLED Display]]
'''Arduino Uno R3:'''
* Der Arduino besitzt unterschiedliche [[Arduino_UNO:_Board_Anatomie | Schnittstellen]], weil der Arduino ein digitaler Mikrocontroller ist, kann er nur <nowiki>&thinsp;</nowiki>5&thinsp;Volt ausgeben oder annehmen.
* Bei einer konstanten <nowiki>&thinsp;</nowiki>5&thinsp;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 <nowiki>&thinsp;</nowiki>5&thinsp;V Signal kaum noch vorhanden und bei einem hohen PWM-Wert liegt das <nowiki>&thinsp;</nowiki>5&thinsp;V 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 (~)


'''Steckbrett:'''<br>
===OLED Display:===
Erklärung zum Arbeiten mit einem Steckbrett [[Steckbrett | (klicken!)]]
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.


'''OLED Display:'''<br>
{| class="wikitable"
Das Display verfügt über vier Pins:
|+ style = "text-align: left"| 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
| '''VCC''' || Pin für die Spannungsversorgung, anzuschließen an den 5V 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.
| '''GND''' || Ground-Pin, anzuschließen an den GND Pin des Mikrocontrollers
|-
| '''SDA ''' || Überträgt Daten oder Adressen
|-
| '''SCL''' || Überträgt den Takt
|}


== '''Aufbau Schaltung''' ==
== Aufbau Schaltung ==
[[Datei:Schaltung_Pong.png|500px|thumb|right|Abb.3 Schaltung Pong Spiel]]
[[Datei:Schaltung_Pong.png|500px|thumb|right|Abb.4 Schaltung Pong Spiel]]
In Abb. 3 wird die Schaltung für das Projekt '''" Arduino Pong Spiel"''' dargestellt.
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.


=='''Arduino Datei erstellen'''==
==Programmierung==
Erstellen der ersten '''Arduino Datei''' ([https://wiki.hshl.de/wiki/index.php/Erste_Schritte_mit_der_Arduino_IDE Link zum Tutorial]).
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''']].
=='''Programmierung Vorkenntnisse'''==
<br>
*Kenntnisse in den '''Programmierrichtlinien''' für die Erstellung von Software. ([[Programmierrichtlinien Einsteiger|Link]])<br>
----
*Grundkenntnisse von Projekt '''1-5''' verstanden haben. [https://wiki.hshl.de/wiki/index.php/Kategorie:Arduino:_Projekt (Link)]
=== Bibliotheken einfügen===
*Grundkenntnisse für das Projekt '''"Arduino Pong Spiel"''' verstehen. ([[Grundkenntnisse Programmierung (Arduino Pong Spiel) |Link]])
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>
 
=='''Programmierung Anleitung'''==
Nachdem alle Schritte 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.<br>


'''Benötigt wird: '''  
'''Benötigt wird: '''  
# Kommunikation zum I2C/TWI Gerät.
# Kommunikation zum I2C/TWI Gerät: <code>'''Wire.h'''</code>
# Kommunikation mit dem SPI Gerät.
# Kommunikation mit dem SPI Gerät:  <code>'''SPI.h'''</code>
# Adafruit GFX Grafik.
# Adafruit GFX Grafik: <code>'''Adafruit_GFX.h'''</code>
# 128x64 and 128x32 OLEDs Displays.
# 128x64 and 128x32 OLEDs Displays: <code>'''Adafruit_SSD1306.h'''</code>


'''Quelltext 1:''' <code>Pong.ino</code>
['''Quelltext 1: ''' <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">
// Benötigte Bibliotheken
// Benötigte Bibliotheken
#include <SPI.h>
#include <SPI.h>
Zeile 91: Zeile 84:
</syntaxhighlight>
</syntaxhighlight>
|}
|}
----


===2) Initialisierung Arduino===
=== Initialisierung Arduino===
Nachdem nun die Bibliotheken hinzugefügt wurden, folgt nun die Initialisierung der benötigten Pins und Variablen.<br>
'''1. Taster initialisieren'''<br>
Wichtig ist, sich vorab Gedanken zu machen, wie man diese anordnet. (siehe Abbildung 3)
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.


====2.1) Taster: ====
['''Quelltext 2: ''' <code>Pong.ino</code>]
Zuerst müssen allen vier Tastern einen Pin am Arduino zugewiesen werden, diese kann man beliebig an den digitalen Schnittstellen anschließen.<br>
Danach werden die Pins mit <code>pinMode();</code> und <code>digitalWrite();</code> initialisiert.
 
'''Quelltext 2:''' <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">
/* Taster PINS */
/* Taster PINS */
const char UP_BUTTON = 2;
const char UP_BUTTON = 2;
Zeile 112: Zeile 103:
const char DOWN_BUTTON_TWO = 5;
const char DOWN_BUTTON_TWO = 5;


void setup() {
void setup()  
/* Taster Initialisieren */
{
pinMode(UP_BUTTON, INPUT);
/* Taster initialisieren */
pinMode(DOWN_BUTTON, INPUT);                 
pinMode(UP_BUTTON, INPUT);
digitalWrite(UP_BUTTON, HIGH);
pinMode(DOWN_BUTTON, INPUT);                 
digitalWrite(DOWN_BUTTON, HIGH);
digitalWrite(UP_BUTTON, HIGH);
digitalWrite(DOWN_BUTTON, HIGH);
      
      
/* Taster zwei */
/* Taster zwei */
pinMode(UP_BUTTON_TWO, INPUT);
pinMode(UP_BUTTON_TWO, INPUT);
pinMode(DOWN_BUTTON_TWO, INPUT);                 
pinMode(DOWN_BUTTON_TWO, INPUT);                 
digitalWrite(UP_BUTTON_TWO, HIGH);
digitalWrite(UP_BUTTON_TWO, HIGH);
digitalWrite(DOWN_BUTTON_TWO, HIGH);
digitalWrite(DOWN_BUTTON_TWO, HIGH);
 
void loop()
{


void loop() {
//Später
}
}
</syntaxhighlight>
</syntaxhighlight>
|}
|}


====2.2) OLED Display====
'''2. OLED Display initialisieren''' <br>
Um das OLED Display zu initialisieren, wird die Bibliothek Adafruit_SSD1306 benötigt.<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.
Hierfür nutzt man die <code>Adafruit_SSD1306 display()</code> Funktion.


'''Quelltext 3:''' <code>Pong.ino</code>
['''Quelltext 3: ''' <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">
/* Deklaration Display, Verbindung zum I2C (SDA, SCL pins) */
/* Deklaration Display, Verbindung zum I2C (SDA, SCL pins) */
const char OLED_RESET; // Reset pin
const char OLED_RESET = 0; // Reset Pin
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
</syntaxhighlight>
</syntaxhighlight>
|}
|}


====2.3) Variablen====
'''3. Variablen initialisieren''' <br>
Auch können vorab Variablen bestimmt werden, die für die Programmierung benötigt werden.<br>
Auch können vorab Variablen bestimmt werden, die für die Programmierung benötigt werden.<br>
Wie die Größe des Displays und die Eigenschaften vom Schläger und Ball.<br>
* Die '''Größe des Displays''' und die '''Ball Rate'''<br>
Zusätzlich ist geplant, eine Punkteanzeige zu entwerfen, wofür zwei Variablen benötigt werden.
* 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:''' <code>Pong.ino</code>
['''Quelltext 4: ''' <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">
const unsigned char PADDLE_RATE = 33;        // const: Konstant, wert bleibt unverändert
const unsigned char BALL_RATE = 16;           
const unsigned char BALL_RATE = 16;          // unsigned long: kann keine negativen Zahlen speichern
const unsigned char PADDLE_HEIGHT = 25;
const unsigned char PADDLE_HEIGHT = 25;


Zeile 165: Zeile 159:
const char SCREEN_HEIGHT = 64;    // OLED Display Höhe
const char SCREEN_HEIGHT = 64;    // OLED Display Höhe


unsigned int Player_one = 0, Player_two = 0;
unsigned int playerOne = 0, playerTwo = 0;
</syntaxhighlight>
</syntaxhighlight>
|}
|}


====2.4) Position vom Ball, Paddle und Spieler auf dem Display ====
'''4. Position vom Ball, Paddle und Spieler auf dem Display festlegen''' <br>
Im nächsten Schritt sollen die Postionen auf dem Display festgelegt werden.<br>
* Benötigte Postionen sind: '''Ball, Spieler 1 (playerOne) und Spieler 2 (playerTwo)'''.<br>
Benötigte Postionen sind: '''Ball, Spieler 1 (Cpu) und Spieler 2 (Player)'''.<br>
* Benötigt wird eine Update-Variable, um den Ball zu bewegen.<br>
Auch werden '''zwei update Variablen''' benötigt, um später den Ball und Schläger bewegen zu können.<br>
* Dieser Werte können nach Geschmack angepasst werden.
Dieser Werte können nach Geschmack angepasst werden.


'''Quelltext 5:''' <code>Pong.ino</code>
['''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="border: none; background-color: #EFF1C1; font-size:14px">
<syntaxhighlight lang="C" style="border: none; background-color: #EFF1C1; font-size:small">
unsigned char Ball_x = 64, Ball_y = 32;                  
unsigned char ballX = 64, ballY = 32;
unsigned char Ball_dir_x = 1, Ball_dir_y = 1;
unsigned char ballDir_x = 1, ballDir_y = 1;


const unsigned char CPU_X = 12;                  
const unsigned char PLAYER_TWO_X = 12;
unsigned char Cpu_y = 16;
unsigned char playerTwo_y = 16;


const unsigned char PLAYER_X = 115;
const unsigned char PLAYER_ONE_X = 115;
unsigned char Player_y = 16;
unsigned char playerOne_y = 16;


unsigned long Ball_update;
unsigned long ballUpdate;
unsigned long Paddle_update;


</syntaxhighlight>
</syntaxhighlight>
|}
|}
----


===3) Display hochfahren===
=== Display hochfahren===
Um später zu sehen, wo man welche Objekte platziert hat, muss das Display hochgefahren werden.<br>
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>
Zusätzlich wird beim Start vom Display ein Timer gesetzt, dieser wird für die Bewegung vom Ball benötigt.<br>
'''Benötigt wird: ''' <code>display.display();</code> und <code>mills();</code> zum Zeitauslesen.     
'''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>
['''Quelltext 6: ''' <code>Pong.ino</code>]
{| 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">
void setup() {
void setup()  
  Serial.begin(9600);
{
Serial.begin(9600);


/* Hochfahren vom Display */
/* Hochfahren vom Display */
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // Starte das Display         
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // Starte das Display         
  display.display();                    // Zeigt das Startbild vom Arduino an
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
unsigned long start = millis();      // Anzahl von Ms zurück, seit Arduino-Board das aktuelle Programm gestartet hat
  delay(1000);
delay(1000);
  display.clearDisplay();            // Löscht das Bild
display.clearDisplay();            // Löscht das Bild


/* Ball Timer zuweisen*/
/* Ball Timer zuweisen*/
  Ball_update = millis();
ballUpdate = millis();
  delay(1000);
delay(1000);
}
}
</syntaxhighlight>
</syntaxhighlight>
|}
|}


====3.1) Display Spielname anzeigen====
''' Display Spielname anzeigen''' <br>
Als Zusatzaufgabe habe ich überlegt, bevor das Spiel startet den Namen '''Pong Spiel''' auf dem Display anzeigen zu lassen.<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.  
 
'''Tipp: ''' Hierfür werden die <code>'''display.set();'''</code> und <code>'''display.println'''();</code> Funktionen benötigt.  


'''Quelltext 7: ''' <code>Pong.ino</code>
['''Quelltext 7: ''' <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">
/* Pong Spiel Namen anzeigen */
/* Pong Spiel Namen anzeigen */
   display.setTextSize(2);
   display.setTextSize(2);
Zeile 244: Zeile 239:
</syntaxhighlight>
</syntaxhighlight>
|}
|}
----


===4) Display Punkteanzeige===
=== Display Punkteanzeige===
Um die Punktanzeige ins Spiel mit einzubringen, werden zwei Methoden benötigt.<br>
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 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>
* 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>
'''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">


/* Punkteanzeigen */
void drawScore()  
void drawScore() {              
{
  display.setTextSize(2);
display.setTextSize(2);
  display.setTextColor(WHITE);
display.setTextColor(WHITE);
  display.setCursor(44, 0);
display.setCursor(43, 0);
  display.println(Player_one);
display.println(playerOne);


  display.setCursor(74, 0);
display.setCursor(73, 0);
  display.println(Player_two);  
display.println(playerTwo);
}
}
/* Punkte zurücksetzten */
/* Punkte zurücksetzten */
void eraseScore() {                              
void eraseScore()  
  display.setTextSize(2);
{
  display.setTextColor(BLACK);
display.setTextSize(2);
  display.setCursor(44, 0);
display.setTextColor(BLACK);
  display.println(Player_one);
display.setCursor(43, 0);
 
display.println(playerOne);
  display.setCursor(74, 0);
 
  display.println(Player_two);
display.setCursor(73, 0);
display.println(playerTwo);
}
}
</syntaxhighlight>
</syntaxhighlight>
|}
|}


===5) Bewegter Ball===
----
Damit der Ball sich auf dem Display bewegt, benötigt man eine Rechenfunktion.<br>
 
'''Tipp:''' Rechne den X und Y Wert + 1 und erstelle eine neue Variable.
=== 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>
['''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
   unsigned long time = millis();              // Zeit-Variable
Zeile 302: Zeile 304:
|}
|}


====5.1) Wände erkennen====
'''1. Wände erkennen''' <br>
Damit der Ball wie gewünscht von den Wänden abprallt, müssen die Wände mit einer If Abfrage erkannt werden.<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>
* Wenn der Ball auf eine Wand trifft, muss die Richtung vom Ball geändert werden.<br>
Zusätzlich soll der Spieler ein Punkt bekommen, wenn die Linke oder Rechte Wand berührt wurde.
* 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 vom Ball erreicht wurde, negiere den Addierer.
 
'''Tipp: ''' Wenn die X oder Y Position von der Wand erreicht wurde, negieren Sie den Addierer.


'''Quelltext 10:''' <code>Pong.ino</code>
['''Quelltext 10: ''' <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">
if (time > Ball_update) {
/* Checkt ob die vertikalen Wände berührt werden */
    /* Neue Ballposition */
  if (New_x == 0) // Wand links
    unsigned char New_x = Ball_x + Ball_dir_x;               // (x+1)
  {                        
    unsigned char New_y = Ball_y + Ball_dir_y;               // (y+1)
    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;
  }


    /* Checkt ob die verticalen Wände berüht werden */
  if (New_x == 127)   // Wand rechts
    if (New_x == 0) {                        // Wand links
  {                   
       Ball_dir_x = -Ball_dir_x;             // Wechselt die Richtung
       ballDir_x = -ballDir_x;           // Wechselt die Richtung
       New_x += Ball_dir_x + Ball_dir_x;
       New_x += ballDir_x + ballDir_x;
       eraseScore();                         // Punkt für Spieler
       eraseScore();                       // Punkt für Spieler 2
       Player_one += 1;
       playerTwo += 1;
       drawScore();
       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>
|}


    }
'''2. Paddel erkennen''' <br>
    if (New_x == 127) {                     // Wand rechts
Auch muss der Ball, wenn er den Schläger berührt, seine Richtung ändern.<br>
      Ball_dir_x = -Ball_dir_x;           // Wechselt die Richtung
 
      New_x += Ball_dir_x + Ball_dir_x;
'''Tipp: ''' Die Position von den Paddeln muss kleiner sein als die Position vom Ball.
      eraseScore();                       // Punkt für den Computer
 
      Player_two += 1;
['''Quelltext 11: ''' <code>Pong.ino</code>]
      drawScore();
{| 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 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;
  }
</syntaxhighlight>
|}
 
'''3. Neue Ballposition anzeigen''' <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>
Außerdem müssen die neuen Variablen übertragen werden auf die alten, um weitere Abläufe zu ermöglichen.<br>


    // Checkt ob die horizontalen Wände berüht werden
'''Tipp: '''Nutze <code>'''display.drawPixel(Name, Name, BLACK/WHITE);'''</code>.
    if (New_y == 0 || New_y == 63) {
      Ball_dir_y = -Ball_dir_y;           // Wechselt die Richtung
      New_y += Ball_dir_y + Ball_dir_y;


     }
['''Quelltext 12: ''' <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">
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();
  }
</syntaxhighlight>
</syntaxhighlight>
|}
|}


====5.2) Paddel erkennen====
-----
Auch muss der Ball, wenn er den Schläger berührt, seine Richtung ändern.
 
'''Tipp: ''' Postion von den Paddeln muss kleiner sein als die Postion vom Ball
=== Boolean Taster===
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>
 
'''Tipp: '''
# Neue Variablen für die Taster mit <code>'''bool'''</code> initialisieren.
# Die alten und neuen Variablen auf <code>'''LOW'''</code> zu setzen, um die Taster schalten zu können.
# Wenn die <code>'''bool'''</code> <code>'''Variable = true'''</code> ist, soll das Display mit <code>'''display.display();'''</code> aktualisiert werden.


'''Quelltext 11:''' <code>Pong.ino</code>
['''Quelltext 13: ''' <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">
// Checkt ob der Spieler 1 Paddel getroffen wurde
bool update = false;                          // Ein bool enthält einen von zwei Werten, true oder false
    if (New_x == CPU_X && New_y >= Cpu_y && New_y <= Cpu_y + PADDLE_HEIGHT) {
unsigned long time = millis();              // Zeit-Variable
      Ball_dir_x = -Ball_dir_x;
 
      New_x += Ball_dir_x + Ball_dir_x;
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);


    // Checkt ob der Spieler 2 Paddel getroffen wurde
if (update)                      // Wenn Variable = true wird display.display(); ausgeführt
    if (New_x == PLAYER_X && New_y >= Player_y && New_y <= Player_y + PADDLE_HEIGHT) {
display.display();
      Ball_dir_x = -Ball_dir_x;
      New_x += Ball_dir_x + Ball_dir_x;
    }
}
}
</syntaxhighlight>
</syntaxhighlight>
|}
|}


== '''Musterlösung''' ==
----
 
=== 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;
  }
  if (DOWN_STATE)
  {
    playerOne_y += 1;
  }
  UP_STATE = DOWN_STATE = false;
 
  if (playerOne_y < 1) playerOne_y = 1;                                    // Um nicht aus dem Bildschirm zu gelangen
  if (playerOne_y + PADDLE_HEIGHT > 63) playerOne_y = 63 - PADDLE_HEIGHT;
  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
  }
  if (DOWN_STATE_TWO)
  {
    playerTwo_y += 1;                      // Paddle 1 nach oben
  }
  UP_STATE_TWO = DOWN_STATE_TWO = false;
 
  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);


Quelle: [https://projecthub.arduino.cc/Krepak/ultrasonic-security-system-a6ea3a Link]
  if (update)                    //hierhin verschieben
  display.display();
}
</syntaxhighlight>
|}
 
== Musterlösung ==
{| 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">
/* Benötigte Bibliotheken */
/* 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>


Zeile 393: Zeile 508:


/* Variablen */
/* Variablen */
const unsigned char PADDLE_RATE = 33;        // const: Konstant, wert bleibt unverändert
const unsigned char BALL_RATE = 16;           
const unsigned char BALL_RATE = 16;          // unsigned long: kann keine negativen Zahlen speichern
const unsigned char PADDLE_HEIGHT = 25;
const unsigned char PADDLE_HEIGHT = 25;


Zeile 400: Zeile 514:
const char SCREEN_HEIGHT = 64;    // OLED Display Höhe
const char SCREEN_HEIGHT = 64;    // OLED Display Höhe


unsigned int Player_one = 0, Player_two = 0;
unsigned int playerOne = 0, playerTwo = 0;


/* Deklaration Display, verbindung zum I2C (SDA, SCL pins) */
/* Deklaration Display, verbindung zum I2C (SDA, SCL pins) */
const char OLED_RESET; // Reset pin
const char OLED_RESET = 0; // Reset pin
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);


 
 
/* 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;                  
unsigned char ballX = 64, ballY = 32;
unsigned char Ball_dir_x = 1, Ball_dir_y = 1;
unsigned char ballDir_x = 1, ballDir_y = 1;


const unsigned char CPU_X = 12;                  
const unsigned char PLAYER_TWO_X = 12;
unsigned char Cpu_y = 16;
unsigned char playerTwo_y = 16;


const unsigned char PLAYER_X = 115;
const unsigned char PLAYER_ONE_X = 115;
unsigned char Player_y = 16;
unsigned char playerOne_y = 16;


unsigned long Ball_update;
unsigned long ballUpdate;
unsigned long Paddle_update;
       
void setup() {
    Serial.begin(9600);
    display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // Starte das Display       


   
void setup()
    display.display();                    // Display Aktualisierung
{
    unsigned long start = millis();      // Anzahl von Ms zurück, seit Arduino-Board das aktuelle Programm gestartet hat
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 */
/* Taster Initialisieren */
  pinMode(UP_BUTTON, INPUT);
  pinMode(UP_BUTTON, INPUT);       // Taster als INPUT festlegen
  pinMode(DOWN_BUTTON, INPUT);              
  pinMode(DOWN_BUTTON, INPUT);
  digitalWrite(UP_BUTTON, HIGH);
  digitalWrite(UP_BUTTON, HIGH);       // Taster anschalten
  digitalWrite(DOWN_BUTTON, HIGH);
  digitalWrite(DOWN_BUTTON, HIGH);
   
 
/* Taster zwei */
/* Taster zwei */
  pinMode(UP_BUTTON_TWO, INPUT);
pinMode(UP_BUTTON_TWO, INPUT);
  pinMode(DOWN_BUTTON_TWO, INPUT);              
pinMode(DOWN_BUTTON_TWO, INPUT);
  digitalWrite(UP_BUTTON_TWO, HIGH);
digitalWrite(UP_BUTTON_TWO, HIGH);
  digitalWrite(DOWN_BUTTON_TWO, HIGH);
digitalWrite(DOWN_BUTTON_TWO, HIGH);
  display.clearDisplay();              // Display alle Pixel ausschalten
}


    while(millis() - start < 2000);   // Solange Millis kleiner als 2000ms ist
/* Punkteanzeige */
 
void drawScore()
    display.display();
{
display.setTextSize(2);
display.setTextColor(WHITE);
display.setCursor(43, 0);
display.println(playerOne);


    Ball_update = millis();
display.setCursor(73, 0);
    delay(1000);
display.println(playerTwo);
}
}
/* 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 */
/* Punkte zurücksetzten */
void eraseScore() {                              
void eraseScore()  
  display.setTextSize(2);
{
  display.setTextColor(BLACK);
display.setTextSize(2);
  display.setCursor(44, 0);
display.setTextColor(BLACK);
  display.println(Player_one);
display.setCursor(43, 0);
 
display.println(playerOne);
  display.setCursor(74, 0);
 
  display.println(Player_two);
display.setCursor(73, 0);
display.println(playerTwo);
}
}


void loop() {
void loop()  
    drawScore();
{
 
drawScore();
    bool update = false;                          // Ein bool enthält einen von zwei Werten, true oder false
 
    unsigned long time = millis();
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;


    static bool Up_state = false;
UP_STATE |= (digitalRead(UP_BUTTON) == LOW);                  // Taster auslesen
    static bool Down_state = false;
DOWN_STATE |= (digitalRead(DOWN_BUTTON) == LOW);
    static bool Up_state_two = false;
UP_STATE_TWO |= (digitalRead(UP_BUTTON_TWO) == LOW);
    static bool Down_state_two = false;
DOWN_STATE_TWO |= (digitalRead(DOWN_BUTTON_TWO) == LOW);
   
    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);


/* Neue Ballposition */
  if (time > ballUpdate)
  {
  unsigned char New_x = ballX + ballDir_x;              // (x+1)
  unsigned char New_y = ballY + ballDir_y;              // (y+1)


   if (time > Ball_update) {
/* Checkt ob die vertikalen Wände berührt werden */
    unsigned char New_x = Ball_x + Ball_dir_x;               // neue Ballposition
   if (New_x == 0) // Wand links
    unsigned char New_y = Ball_y + Ball_dir_y;
  {                        
    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;
  }


    // Checkt ob die verticalen Wände berüht werden
  if (New_x == 127)   // Wand rechts
    if (New_x == 0) {                        // Wand links
  {                   
       Ball_dir_x = -Ball_dir_x;             // Wechselt die Richtung
       ballDir_x = -ballDir_x;           // Wechselt die Richtung
       New_x += Ball_dir_x + Ball_dir_x;
       New_x += ballDir_x + ballDir_x;
       eraseScore();                         // Punkt für Spieler
       eraseScore();                       // Punkt für Spieler 2
       Player_one = Player_one + 1;
       playerTwo += 1;
       drawScore();
       drawScore();
         
      New_x = 64;                         // Ball Reset
         
      New_y = 32;
        }
    }
        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
// Checkt ob die horizontalen Wände berührt werden
        if(New_y == 0 || New_y == 63) {
  if (New_y == 0 || New_y == 63)  
            Ball_dir_y = -Ball_dir_y;          // Wechselt die Richtung
  {
            New_y += Ball_dir_y + Ball_dir_y;
    ballDir_y = -ballDir_y;          // Wechselt die Richtung
           
    New_y += ballDir_y + ballDir_y;
        }
  }


        // Checkt ob der Computer Paddel getroffen wurde
// Checkt, ob der Spieler 1 Paddel getroffen wurde
        if(New_x == CPU_X && New_y >= Cpu_y && New_y <= Cpu_y + PADDLE_HEIGHT) {
  if (New_x == PLAYER_ONE_X && New_y >= playerOne_y && New_y <= playerOne_y + PADDLE_HEIGHT)  
            Ball_dir_x = -Ball_dir_x;
  {
            New_x += Ball_dir_x + Ball_dir_x;
    ballDir_x = -ballDir_x;
        }
    New_x += ballDir_x + ballDir_x;
  }


        // Checkt ob der Spieler Paddel getroffen wurde
// Checkt, ob der Spieler 2 Paddel getroffen wurde
        if(New_x == PLAYER_X && New_y >= Player_y && New_y <= Player_y + PADDLE_HEIGHT) {
  if (New_x == PLAYER_TWO_X && New_y >= playerTwo_y && New_y <= playerTwo_y + PADDLE_HEIGHT) {
            Ball_dir_x = -Ball_dir_x;
    ballDir_x = -ballDir_x;
            New_x += Ball_dir_x + Ball_dir_x;
    New_x += ballDir_x + ballDir_x;
        }
  }
       
    display.drawPixel(ballX, ballY, BLACK);
        display.drawPixel(Ball_x, Ball_y, BLACK);
    display.drawPixel(New_x, New_y, WHITE);
        display.drawPixel(New_x, New_y, WHITE);
    ballX = New_x;
        Ball_x = New_x;
    ballY = New_y;
        Ball_y = New_y;


        Ball_update += BALL_RATE;
    ballUpdate += BALL_RATE;
    update = true;              // true ~ display.display();
  }


        update = true;              // updated bool auf true
/* Spieler 1 Paddel */
    }
  display.drawFastVLine(PLAYER_ONE_X, playerOne_y, PADDLE_HEIGHT, BLACK);
       
  if (UP_STATE)  
        display.drawFastVLine(CPU_X, Cpu_y, PADDLE_HEIGHT, BLACK);
  {
        if(Up_state_two) {
  playerOne_y -= 1;
            Cpu_y -= 1;
  }
        }
  if (DOWN_STATE)  
          if(Down_state_two) {
  {
            Cpu_y += 1;
    playerOne_y += 1;
        }
  }
        Up_state_two = Down_state_two = false;
  UP_STATE = DOWN_STATE = false;
        if(Cpu_y < 1) Cpu_y = 1;
 
        if(Cpu_y + PADDLE_HEIGHT > 63) Cpu_y = 63 - PADDLE_HEIGHT;
  if (playerOne_y < 1) playerOne_y = 1;                                   // Um nicht aus dem Bildschirm zu gelangen
        display.drawFastVLine(CPU_X, Cpu_y, PADDLE_HEIGHT, WHITE);
  if (playerOne_y + PADDLE_HEIGHT > 63) playerOne_y = 63 - PADDLE_HEIGHT;
       
  display.drawFastVLine(PLAYER_ONE_X, playerOne_y, PADDLE_HEIGHT, WHITE);


        // Spieler Paddel
  update = true;
        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;
/* Spieler 2 Paddel */
  display.drawFastVLine(PLAYER_TWO_X, playerTwo_y, PADDLE_HEIGHT, BLACK);
  if (UP_STATE_TWO)
  {
    playerTwo_y -= 1;                      // Paddle 1 nach unten
  }
  if (DOWN_STATE_TWO)
  {
    playerTwo_y += 1;                      // Paddle 1 nach oben
  }
  UP_STATE_TWO = DOWN_STATE_TWO = false;
 
  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();
}


    if(update)
        display.display();
}
</syntaxhighlight>
</syntaxhighlight>
|}
|}
[https://github.com/shveytank/Arduino_Pong_Game Quelle]


<br>
<br>
----
----
→ zurück zum Hauptartikel: [[Konzipierung_und_Evaluierung_von_Arduino-Projekten_verschiedener_Schwierigkeitsgrade_für_die_Lehre | BA: Arduino-Projekte für die Lehre]]
'''→ zurück zum Hauptartikel: [[Konzipierung_und_Evaluierung_von_Arduino-Projekten_verschiedener_Schwierigkeitsgrade_für_die_Lehre | BA: Arduino-Projekte für die Lehre]]'''

Aktuelle Version vom 12. September 2023, 06: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