Arduino Retro Gaming Mit einem OLED-Display

Haben Sie sich jemals gefragt, wie viel Arbeit Sie brauchen, um Ihre eigenen Retro-Spiele zu schreiben? Wie einfach ist Pong für den Arduino zu codieren?

Haben Sie sich jemals gefragt, wie viel Arbeit Sie brauchen, um Ihre eigenen Retro-Spiele zu schreiben?  Wie einfach ist Pong für den Arduino zu codieren?
Werbung

Haben Sie sich jemals gefragt, wie viel Arbeit Sie brauchen, um Ihre eigenen Retro-Spiele zu schreiben? Wie einfach ist Pong für den Arduino zu codieren? Begleiten Sie mich, während ich Ihnen zeige, wie man eine Arduino-betriebene Mini-Retro-Spielekonsole baut und wie man Pong von Grund auf neu programmiert. Hier ist das Endergebnis:

Bauplan

Dies ist eine ziemlich einfache Schaltung. Ein Potentiometer (Pot) steuert das Spiel und ein OLED-Display wird vom Arduino angesteuert. Dies wird auf einem Steckbrett hergestellt, aber Sie können dies zu einem permanenten Stromkreis machen und es in einem Fall installieren. Wir haben über Pong neu erstellt Wie das klassische Pong-Spiel mit Arduino neu zu erstellen Wie das klassische Pong-Spiel mit Arduino Pong neu zu erstellen war das erste Videospiel, das den Massenmarkt erreicht. Zum ersten Mal in der Geschichte wurde das Konzept eines "Videospiels" dank des Atari 2600 -... Read More vorher, aber heute werde ich Ihnen zeigen, wie man den Code von Grund auf neu schreibt, in das Haus der Familie gebracht, und jeden Teil zerlegen.

Was du brauchst

Retro-Arduino-Setup

Folgendes brauchen Sie:

  • 1 x Arduino (jedes Modell)
  • 1 x 10k Potentiometer
  • 1 x 0, 96 "I2C OLED-Display
  • 1 x Steckbrett
  • Assorted männlich> männlich Hookup Drähte

Diymall 0, 96 "Zoll I2c IIC Serial 128x64 Oled LCD LED Weiß Anzeigemodul für Arduino 51 Msp420 Stim32 SCR Diymall 0, 96" Zoll I2c IIC Serial 128x64 Oled LCD LED Weiß Anzeigemodul für Arduino 51 Msp420 Stim32 SCR Jetzt Kaufen bei Amazon 9, 99 €

Jeder Arduino sollte funktionieren, schauen Sie sich unsere Kaufanleitung Arduino Buying Guide an: Welchen Board sollten Sie bekommen? Arduino Einkaufsführer: Welches Board sollten Sie bekommen? Es gibt so viele verschiedene Arten von Arduino Boards da draußen, es wäre dir vergeben, wenn du verwirrt bist. Was sollten Sie für Ihr Projekt kaufen? Lassen Sie uns helfen, mit diesem Arduino Einkaufsführer! Lesen Sie mehr, wenn Sie nicht sicher sind, welches Modell Sie kaufen möchten.

Diese OLED-Displays sind sehr cool. Sie können normalerweise in weiß, blau, gelb oder einer Mischung der drei gekauft werden. Sie existieren in voller Farbe, jedoch fügen sie der Komplexität und den Kosten dieses Projekts eine ganz andere Ebene hinzu.

Die Rennbahn

Dies ist eine ziemlich einfache Schaltung. Wenn Sie nicht viel Erfahrung mit Arduino haben, sehen Sie sich diese Anfänger-Projekte an. 10 Große Arduino-Projekte für Anfänger 10 Große Arduino-Projekte für Anfänger Das Abschließen eines Arduino-Projekts gibt Ihnen ein Gefühl der Zufriedenheit wie kein anderer. Die meisten Anfänger sind jedoch nicht sicher, wo sie anfangen sollen, und selbst Anfängerprojekte können ziemlich entmutigend wirken. Lesen Sie zuerst.

Hier ist es:

Pong Steckbrett

Betrachten Sie die Vorderseite des Topfes, verbinden Sie den linken Pin mit + 5V und den rechten Pin mit Masse . Verbinden Sie den mittleren Pin mit dem analogen Pin 0 (A0).

Das OLED-Display wird über das I2C-Protokoll verbunden. Verbinden Sie VCC und GND mit dem Arduino + 5V und Masse . Verbinden Sie SCL mit Analog fünf ( A5 ). Verbinden Sie SDA mit Analog 4 ( A4 ). Der Grund, warum dies mit den analogen Pins verbunden ist, ist einfach; Diese Pins enthalten die für das I2C-Protokoll erforderliche Schaltung. Stellen Sie sicher, dass diese korrekt verbunden und nicht gekreuzt sind. Die genauen Pins variieren je nach Modell, aber A4 und A5 werden bei Nano und Uno verwendet. Überprüfen Sie die Drahtbibliotheksdokumentation für Ihr Modell, wenn Sie kein Arduino oder Nano verwenden.

Topf-Test

Laden Sie diesen Testcode hoch (achten Sie darauf, die richtige Karte und den richtigen Port aus den Menüs Tools > Board und Tools > Port auszuwählen):

void setup() { // put your setup code here, to run once: Serial.begin(9600); // setup serial } void loop() { // put your main code here, to run repeatedly: Serial.println(analogRead(A0)); // print the value from the pot delay(500); } 

Öffnen Sie nun den seriellen Monitor ( oben rechts > Serial Monitor ) und drehen Sie den Pot. Sie sollten den auf dem seriellen Monitor angezeigten Wert sehen. Voll gegen den Uhrzeigersinn sollte Null sein, und im Uhrzeigersinn sollte 1023 sein :

Pong seriellen Monitor

Sie werden dies später anpassen, aber für jetzt ist es in Ordnung. Wenn nichts passiert oder sich der Wert ändert, ohne dass Sie etwas tun, trennen Sie die Verbindung und überprüfen Sie die Schaltung erneut.

OLED-Test

OLED-Grafiken

Das OLED-Display ist etwas komplexer zu konfigurieren. Sie müssen zwei Bibliotheken installieren, um das Display zuerst zu steuern. Laden Sie die Adafruit_SSD1306- und Adafruit-GFX-Bibliotheken von Github herunter. Kopieren Sie die Dateien in Ihren Bibliotheksordner. Dies hängt von Ihrem Betriebssystem ab:

  • Mac OS: / Benutzer / Benutzername / Dokumente / Arduino / Bibliotheken
  • Linux: / home / Benutzername / Skizzenbuch
  • Windows: / Benutzer / Arduino / Bibliotheken

Laden Sie jetzt eine Testskizze hoch. Gehen Sie zu Datei > Beispiele > Adafruit SSD1306 > ssd1306_128x64_i2c . Dies sollte Ihnen eine große Skizze mit vielen Grafiken geben:

OLED-Grafiken

Wenn nach dem Hochladen nichts passiert, trennen Sie die Verbindungen und überprüfen Sie sie erneut. Wenn sich die Beispiele nicht in den Menüs befinden, müssen Sie möglicherweise Ihre Arduino IDE neu starten.

Der Code

Jetzt ist es Zeit für den Code. Ich werde jeden Schritt erklären, also spring bis zum Ende, wenn du es nur zum Laufen bringen willst. Dies ist eine angemessene Menge an Code, wenn Sie sich also nicht sicher fühlen, lesen Sie diese 10 kostenlose Ressourcen Lernen Sie Code: 10 kostenlose und fantastische Online-Ressourcen, um Ihre Fähigkeiten zu verbessern Lernen Sie Code: 10 kostenlose und fantastische Online-Ressourcen, um Ihre Fähigkeiten Codierung. Ein Thema, das von vielen vermieden wird. Es gibt eine Fülle von kostenlosen Ressourcen und Tools, die alle online verfügbar sind. Sicher, Sie könnten einige Kurse zu diesem Thema in einem nahe gelegenen ... Lesen Sie mehr, um zu lernen, zu programmieren.

Beginnen Sie mit dem Einbinden der notwendigen Bibliotheken:

 #include #include #include #include 

SPI und WIRE sind zwei Arduino-Bibliotheken für die I2C-Kommunikation. Adafruit_GFX und Adafruit_SSD1306 sind die zuvor installierten Bibliotheken.

Als nächstes konfigurieren Sie die Anzeige:

 Adafruit_SSD1306 display(4); 

Richte dann alle Variablen ein, die zum Ausführen des Spiels benötigt werden:

 int resolution[2] = {128, 64}, ball[2] = {20, (resolution[1] / 2)}; const int PIXEL_SIZE = 8, WALL_WIDTH = 4, PADDLE_WIDTH = 4, BALL_SIZE = 4, SPEED = 3; int playerScore = 0, aiScore = 0, playerPos = 0, aiPos = 0; char ballDirectionHori = 'R', ballDirectionVerti = 'S'; boolean inProgress = true; 

Diese speichern alle Daten, die für das Spiel notwendig sind. Einige davon speichern den Ort des Balls, die Größe des Bildschirms, den Standort des Spielers und so weiter. Beachten Sie, dass einige davon konstant sind, was bedeutet, dass sie konstant sind und sich niemals ändern werden. Dadurch kann der Arduino-Compiler die Dinge etwas beschleunigen.

Die Bildschirmauflösung und die Ballposition werden in Arrays gespeichert. Arrays sind Sammlungen ähnlicher Dinge, und für den Ball speichern Sie die Koordinaten ( X und Y ). Der Zugriff auf Elemente in Arrays ist einfach (fügen Sie diesen Code nicht in Ihre Datei ein):

 resolution[1]; 

Da Arrays bei Null beginnen, wird dadurch das zweite Element im Auflösungsfeld ( 64 ) zurückgegeben. Das Aktualisieren von Elementen ist noch einfacher (diesen Code nicht erneut einschließen):

 ball[1] = 15; 

Inside void setup (), konfigurieren Sie die Anzeige:

 void setup() { display.begin(SSD1306_SWITCHCAPVCC, 0x3C); display.display(); } 

Die erste Zeile teilt der Adafruit-Bibliothek mit, welche Dimensionen und welches Kommunikationsprotokoll Ihr Bildschirm verwendet (in diesem Fall 128 x 64 und I2C ). Die zweite Zeile ( display.display () ) teilt dem Bildschirm mit, was im Puffer gespeichert ist (was nichts ist).

Erstellen Sie zwei Methoden namens DrawBall und EraseBall :

 void drawBall(int x, int y) { display.drawCircle(x, y, BALL_SIZE, WHITE); } void eraseBall(int x, int y) { display.drawCircle(x, y, BALL_SIZE, BLACK); } 

Diese nehmen die x- und y- Koordinaten des Balls und zeichnen ihn auf dem Bildschirm mit der drawCircle- Methode aus den Display-Bibliotheken. Dies verwendet die zuvor definierte Konstante BALL_SIZE . Versuchen Sie dies zu ändern und sehen Sie, was passiert. Diese drawCircle-Methode akzeptiert eine Pixelfarbe - SCHWARZ oder WEISS . Da es sich um eine monochrome Anzeige (eine Farbe) handelt, entspricht Weiß einem Pixel, das eingeschaltet ist, und Schwarz deaktiviert das Pixel.

Erstellen Sie nun eine Methode namens moveAi :

 void moveAi() { eraseAiPaddle(aiPos); if (ball[1]>aiPos) { ++aiPos; } else if (ball[1]< aiPos) { --aiPos; } drawAiPaddle(aiPos); } 

Diese Methode behandelt das Bewegen des Artificial Intelligence- oder AI- Players. Dies ist ein ziemlich einfacher Computergegner - Wenn der Ball über dem Paddel ist, gehe nach oben. Es ist unter dem Paddel, bewegen Sie sich nach unten. Ganz einfach, aber es funktioniert gut. Die Inkrement- und Dekrement-Symbole werden verwendet ( ++ aiPos und -aiPos ), um eins von der aiPosition zu addieren oder zu subtrahieren. Sie können eine größere Zahl addieren oder subtrahieren, damit sich die KI schneller bewegt und daher schwerer zu schlagen ist. Hier ist, wie Sie das tun würden:

 aiPos += 2; 

Und:

 aiPos -= 2; 

Die Zeichen Plus Equals und Minus Equals sind Abkürzungen zum Addieren oder Subtrahieren von zwei von / zum aktuellen Wert von aiPos. Hier ist eine andere Möglichkeit, das zu tun:

 aiPos = aiPos + 2; 

und

 aiPos = aiPos - 1; 

Beachten Sie, wie diese Methode das Paddle zuerst löscht und dann erneut zeichnet. Das muss so gemacht werden. Wenn die neue Position des Paddels gezeichnet würde, würde es zwei überlappende Paddel auf dem Bildschirm geben.

Die drawNet- Methode verwendet zwei Schleifen, um das Netz zu zeichnen:

 void drawNet() { for (int i = 0; i< (resolution[1] / WALL_WIDTH); ++i) { drawPixel(((resolution[0] / 2) - 1), i * (WALL_WIDTH) + (WALL_WIDTH * i), WALL_WIDTH); } } 

Dies verwendet die Variablen WALL_WIDTH, um seine Größe festzulegen .

Erstellen Sie Methoden namens DrawPixels und ErasePixels . Genau wie bei den Ballmethoden unterscheidet sich die Farbe der Pixel nur zwischen den beiden:

 void drawPixel(int posX, int posY, int dimensions) { for (int x = 0; x< dimensions; ++x) { for (int y = 0; y< dimensions; ++y) { display.drawPixel((posX + x), (posY + y), WHITE); } } } void erasePixel(int posX, int posY, int dimensions) { for (int x = 0; x< dimensions; ++x) { for (int y = 0; y< dimensions; ++y) { display.drawPixel((posX + x), (posY + y), BLACK); } } } 

Beide Methoden verwenden wiederum zwei for- Schleifen, um eine Gruppe von Pixeln zu zeichnen. Anstatt jedes Pixel mit der drawPixel- Methode zeichnen zu müssen, zeichnen die Loops basierend auf den gegebenen Dimensionen eine Gruppe von Pixeln.

Die drawScore- Methode verwendet die Textfunktionen der Bibliothek, um den Spieler- und AI-Wert auf den Bildschirm zu schreiben. Diese sind in playerScore und aiScore gespeichert:

 void drawScore() { display.setTextSize(2); display.setTextColor(WHITE); display.setCursor(45, 0); display.println(playerScore); display.setCursor(75, 0); display.println(aiScore); } 

Diese Methode hat auch ein EraseScore- Gegenstück, das die Pixel auf Schwarz oder Aus setzt.

Die letzten vier Methoden sind sehr ähnlich. Sie zeichnen und löschen die Player- und AI-Paddle:

 void erasePlayerPaddle(int row) { erasePixel(0, row - (PADDLE_WIDTH * 2), PADDLE_WIDTH); erasePixel(0, row - PADDLE_WIDTH, PADDLE_WIDTH); erasePixel(0, row, PADDLE_WIDTH); erasePixel(0, row + PADDLE_WIDTH, PADDLE_WIDTH); erasePixel(0, row + (PADDLE_WIDTH + 2), PADDLE_WIDTH); } 

Beachten Sie, wie sie die ErasePixel- Methode früher aufrufen . Diese Methoden zeichnen und löschen das entsprechende Paddel.

Es gibt ein bisschen mehr Logik in der Hauptschleife. Hier ist der ganze Code:

 #include #include #include #include Adafruit_SSD1306 display(4); int resolution[2] = {128, 64}, ball[2] = {20, (resolution[1] / 2)}; const int PIXEL_SIZE = 8, WALL_WIDTH = 4, PADDLE_WIDTH = 4, BALL_SIZE = 4, SPEED = 3; int playerScore = 0, aiScore = 0, playerPos = 0, aiPos = 0; char ballDirectionHori = 'R', ballDirectionVerti = 'S'; boolean inProgress = true; void setup() { display.begin(SSD1306_SWITCHCAPVCC, 0x3C); display.display(); } void loop() { if (aiScore>9 || playerScore>9) { // check game state inProgress = false; } if (inProgress) { eraseScore(); eraseBall(ball[0], ball[1]); if (ballDirectionVerti == 'U') { // move ball up diagonally ball[1] = ball[1] - SPEED; } if (ballDirectionVerti == 'D') { // move ball down diagonally ball[1] = ball[1] + SPEED; } if (ball[1] = resolution[1]) { // bounce the ball off the bottom ballDirectionVerti = 'U'; } if (ballDirectionHori == 'R') { ball[0] = ball[0] + SPEED; // move ball if (ball[0]>= (resolution[0] - 6)) { // ball is at the AI edge of the screen if ((aiPos + 12)>= ball[1] && (aiPos - 12) (aiPos + 4)) { // deflect ball down ballDirectionVerti = 'D'; } else if (ball[1]< (aiPos - 4)) { // deflect ball up ballDirectionVerti = 'U'; } else { // deflect ball straight ballDirectionVerti = 'S'; } // change ball direction ballDirectionHori = 'L'; } else { // GOAL! ball[0] = 6; // move ball to other side of screen ballDirectionVerti = 'S'; // reset ball to straight travel ball[1] = resolution[1] / 2; // move ball to middle of screen ++playerScore; // increase player score } } } if (ballDirectionHori == 'L') { ball[0] = ball[0] - SPEED; // move ball if (ball[0] = ball[1] && (playerPos - 12) (playerPos + 4)) { // deflect ball down ballDirectionVerti = 'D'; } else if (ball[1]<(playerPos - 4)) { // deflect ball up ballDirectionVerti = 'U'; } else { // deflect ball straight ballDirectionVerti = 'S'; } // change ball direction ballDirectionHori = 'R'; } else { ball[0] = resolution[0] - 6; // move ball to other side of screen ballDirectionVerti = 'S'; // reset ball to straight travel ball[1] = resolution[1] / 2; // move ball to middle of screen ++aiScore; // increase AI score } } } drawBall(ball[0], ball[1]); erasePlayerPaddle(playerPos); playerPos = analogRead(A2); // read player potentiometer playerPos = map(playerPos, 0, 1023, 8, 54); // convert value from 0 - 1023 to 8 - 54 drawPlayerPaddle(playerPos); moveAi(); drawNet(); drawScore(); } else { // somebody has won display.clearDisplay(); display.setTextSize(4); display.setTextColor(WHITE); display.setCursor(0, 0); // figure out who if (aiScore>playerScore) { display.println("YOU LOSE!"); } else if (playerScore>aiScore) { display.println("YOU WIN!"); } } display.display(); } void moveAi() { // move the AI paddle eraseAiPaddle(aiPos); if (ball[1]>aiPos) { ++aiPos; } else if (ball[1]< aiPos) { --aiPos; } drawAiPaddle(aiPos); } void drawScore() { // draw AI and player scores display.setTextSize(2); display.setTextColor(WHITE); display.setCursor(45, 0); display.println(playerScore); display.setCursor(75, 0); display.println(aiScore); } void eraseScore() { // erase AI and player scores display.setTextSize(2); display.setTextColor(BLACK); display.setCursor(45, 0); display.println(playerScore); display.setCursor(75, 0); display.println(aiScore); } void drawNet() { for (int i = 0; i< (resolution[1] / WALL_WIDTH); ++i) { drawPixel(((resolution[0] / 2) - 1), i * (WALL_WIDTH) + (WALL_WIDTH * i), WALL_WIDTH); } } void drawPixel(int posX, int posY, int dimensions) { // draw group of pixels for (int x = 0; x< dimensions; ++x) { for (int y = 0; y< dimensions; ++y) { display.drawPixel((posX + x), (posY + y), WHITE); } } } void erasePixel(int posX, int posY, int dimensions) { // erase group of pixels for (int x = 0; x< dimensions; ++x) { for (int y = 0; y< dimensions; ++y) { display.drawPixel((posX + x), (posY + y), BLACK); } } } void erasePlayerPaddle(int row) { erasePixel(0, row - (PADDLE_WIDTH * 2), PADDLE_WIDTH); erasePixel(0, row - PADDLE_WIDTH, PADDLE_WIDTH); erasePixel(0, row, PADDLE_WIDTH); erasePixel(0, row + PADDLE_WIDTH, PADDLE_WIDTH); erasePixel(0, row + (PADDLE_WIDTH + 2), PADDLE_WIDTH); } void drawPlayerPaddle(int row) { drawPixel(0, row - (PADDLE_WIDTH * 2), PADDLE_WIDTH); drawPixel(0, row - PADDLE_WIDTH, PADDLE_WIDTH); drawPixel(0, row, PADDLE_WIDTH); drawPixel(0, row + PADDLE_WIDTH, PADDLE_WIDTH); drawPixel(0, row + (PADDLE_WIDTH + 2), PADDLE_WIDTH); } void drawAiPaddle(int row) { int column = resolution[0] - PADDLE_WIDTH; drawPixel(column, row - (PADDLE_WIDTH * 2), PADDLE_WIDTH); drawPixel(column, row - PADDLE_WIDTH, PADDLE_WIDTH); drawPixel(column, row, PADDLE_WIDTH); drawPixel(column, row + PADDLE_WIDTH, PADDLE_WIDTH); drawPixel(column, row + (PADDLE_WIDTH * 2), PADDLE_WIDTH); } void eraseAiPaddle(int row) { int column = resolution[0] - PADDLE_WIDTH; erasePixel(column, row - (PADDLE_WIDTH * 2), PADDLE_WIDTH); erasePixel(column, row - PADDLE_WIDTH, PADDLE_WIDTH); erasePixel(column, row, PADDLE_WIDTH); erasePixel(column, row + PADDLE_WIDTH, PADDLE_WIDTH); erasePixel(column, row + (PADDLE_WIDTH * 2), PADDLE_WIDTH); } void drawBall(int x, int y) { display.drawCircle(x, y, BALL_SIZE, WHITE); } void eraseBall(int x, int y) { display.drawCircle(x, y, BALL_SIZE, BLACK); } 

Hier kommt es auf Folgendes an:

OLED Pong

Sobald Sie mit dem Code vertraut sind, können Sie zahlreiche Änderungen vornehmen:

  • Füge ein Menü für Schwierigkeitsgrade hinzu (verändere AI und Ballgeschwindigkeit).
  • Fügen Sie dem Ball oder der KI eine zufällige Bewegung hinzu.
  • Füge einen weiteren Pot für zwei Spieler hinzu.
  • Fügen Sie eine Pause-Schaltfläche hinzu.

Werfen Sie einen Blick auf diese Retro-Spiele Pi Zero Projekte 5 Retro Gaming Projekte mit dem Raspberry Pi Zero 5 Retro Gaming Projekte mit dem Raspberry Pi Zero Der Raspberry Pi Zero hat die DIY- und Homebrew-Welt im Sturm erobert und alte Projekte überarbeitet und inspirierende Newcomer, besonders in den fiebrigen Gedanken der Retro-Gaming-Fans. Weiterlesen .

Hast du Pong mit diesem Code programmiert? Welche Änderungen haben Sie vorgenommen? Lassen Sie mich in den Kommentaren unten wissen, ich würde gerne ein paar Bilder erscheinen!

In this article