Arduino Retro Gaming con display OLED

Arduino Retro Gaming con display OLED / Fai da te

Vi siete mai chiesti quanto lavoro ci vuole per scrivere i propri giochi retrò? Quanto è facile codificare Pong per l'Arduino? Unisciti a me mentre ti mostro come costruire una mini console per giochi retrò retroata con Arduino e come codificare Pong da zero. Ecco il risultato finale:

Piano di costruzione

Questo è un circuito abbastanza semplice. UN potenziometro (pot) controllerà il gioco, e un display OLED sarà guidato da Arduino. Questo verrà prodotto su una breadboard, tuttavia potresti voler rendere questo circuito permanente e installarlo in una custodia. Abbiamo scritto di ricreare Pong Come ricreare il classico gioco Pong usando Arduino Come ricreare il classico gioco Pong Usando Arduino Pong è stato il primo videogioco in assoluto che ha raggiunto il mercato di massa. Per la prima volta nella storia, il concetto di "videogioco" è stato portato nella casa di famiglia, grazie all'Atari 2600 - ... Leggi di più prima, comunque oggi ti mostrerò come scrivere il codice da zero e spezzare giù ogni parte.

Quello di cui hai bisogno

Ecco di cosa hai bisogno:

  • 1 x Arduino (qualsiasi modello)
  • 1 x 10k Potenziometro
  • Display OLED I2C da 1 x 0,96 "
  • 1 x tagliere
  • Fili di collegamento maschio> maschio assortiti

DIYmall 0.96 "pollici I2c IIC seriale 128x64 Oled LCD Display a LED bianco per Arduino 51 Msp420 Stim32 SCR DIYmall 0.96" pollici I2c IIC seriale 128x64 Oled LCD Display a LED bianco per Arduino 51 Msp420 Stim32 SCR Acquista ora su Amazon $ 8,99

Qualsiasi Arduino dovrebbe funzionare, quindi consulta la nostra guida all'acquisto Guida all'acquisto di Arduino: quale scheda dovresti acquistare? Guida all'acquisto di Arduino: quale scheda si dovrebbe ottenere? Ci sono così tanti diversi tipi di tavole Arduino là fuori, ti verrebbe perdonato per essere stato confuso. Quale dovresti comprare per il tuo progetto? Aiutaci, con questa guida all'acquisto di Arduino! Leggi di più se non sei sicuro del modello da acquistare.

Questi display OLED sono molto interessanti. Di solito possono essere acquistati in bianco, blu, giallo o una miscela dei tre. Esistono a colori, tuttavia questi aggiungono un altro livello alla complessità e al costo di questo progetto.

Il circuito

Questo è un circuito abbastanza semplice. Se non hai molta esperienza con Arduino, dai un'occhiata a questi progetti per principianti 15 Grandi progetti Arduino per principianti 15 Grandi progetti Arduino per principianti Interessato ad Arduino ma non sapendo da dove cominciare? Ecco alcuni dei nostri migliori progetti Arduino per principianti per iniziare! Per saperne di più prima.

Ecco qui:

Guardando la parte anteriore del piatto, collega il perno sinistro a +5V e il pin giusto a terra. Collegare il pin centrale a pin analogico 0 (A0).

Il display OLED è collegato tramite il protocollo I2C. Collegare VCC e GND per l'Arduino +5V e terra. Collegare SCL a analogico cinque (A5). Collegare SDA a analogico 4 (A4). Il motivo per cui è collegato ai pin analogici è semplice; questi pin contengono la circuiteria richiesta per il protocollo I2C. Assicurarsi che siano collegati correttamente e non incrociati. I pin esatti varieranno in base al modello, ma A4 e A5 vengono utilizzati su Nano e Uno. Controlla la documentazione della libreria Wire per il tuo modello se non stai utilizzando un Arduino o un Nano.

Pot Test

Carica questo codice di test (assicurati di selezionare la scheda e la porta corrette da Utensili > Tavola e Utensili > Porta menu):

void setup () // inserisci qui il tuo codice di configurazione, da eseguire una volta: Serial.begin (9600); // setup serial void loop () // inserisci qui il tuo codice principale, per eseguirlo ripetutamente: Serial.println (analogRead (A0)); // stampa il valore dal ritardo del potenziometro (500); 

Ora apri il monitor seriale (In alto a destra > Monitor seriale) e girare il piatto. Dovresti vedere il valore visualizzato sul monitor seriale. Dovrebbe essere completamente in senso antiorario zero, e completamente in senso orario dovrebbe essere 1023:

La regolerai in seguito, ma per ora va bene. Se non succede nulla, o il valore cambia senza che tu faccia nulla, disconnetti e ricontrolla il circuito.

Test OLED

Il display OLED è leggermente più complesso da configurare. È necessario installare due librerie per guidare prima il display. Scarica le librerie Adafruit_SSD1306 e Adafruit-GFX da Github. Copia i file nella cartella delle tue librerie. Questo varia a seconda del tuo sistema operativo:

  • Mac OS: / Users / nomeutente / Documenti / Arduino / librerie
  • Linux: / Home / nomeutente / Sketchbook
  • Finestre: / Utenti / Arduino / librerie

Ora carica uno schizzo di prova. Vai a File > Esempi > Adafruit SSD1306 > ssd1306_128x64_i2c. Questo dovrebbe darti un grande schizzo contenente molti elementi grafici:

Se non succede nulla dopo il caricamento, disconnettere e ricontrollare le connessioni. Se gli esempi non sono nei menu, potrebbe essere necessario riavviare il tuo IDE Arduino.

Il codice

Ora è il momento per il codice. Spiegherò ogni passo, quindi salta alla fine se vuoi solo farlo funzionare. Questa è una buona quantità di codice, quindi se non ti senti sicuro, dai un'occhiata a queste 10 risorse gratuite. Impara a codificare: 10 risorse online gratuite e fantastiche per affinare le tue competenze. Impara a codificare: 10 risorse online gratuite e fantastiche per affinare il tuo Codifica delle competenze. Un argomento che viene evitato da molti. Ci sono un'abbondanza di risorse e strumenti gratuiti, tutti disponibili online. Certo, potresti seguire alcuni corsi sull'argomento in un vicino ... Leggi altro per imparare a programmare.

Inizia includendo le librerie necessarie:

#includere  #includere  #includere  #includere 

SPI e FILO sono due librerie Arduino per la gestione della comunicazione I2C. Adafruit_GFX e Adafruit_SSD1306 sono le librerie che hai installato in precedenza.

Quindi, configura il display:

Display Adafruit_SSD1306 (4);

Quindi imposta tutte le variabili necessarie per eseguire il gioco:

int resolution [2] = 128, 64, ball [2] = 20, (risoluzione [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'; booleano inProgress = true;

Questi memorizzano tutti i dati necessari per eseguire il gioco. Alcuni di questi memorizzano la posizione della palla, le dimensioni dello schermo, la posizione del giocatore e così via. Notate come alcuni di questi sono const nel senso che sono costanti e non cambieranno mai. Ciò consente al compilatore Arduino di velocizzare le cose.

La risoluzione dello schermo e la posizione della palla sono memorizzati in array. Gli array sono raccolte di oggetti simili e, per la palla, memorizzano le coordinate (X e Y). L'accesso agli elementi negli array è facile (non includere questo codice nel file):

risoluzione [1];

Poiché le matrici partono da zero, ciò restituirà il secondo elemento nell'array di risoluzione (64). Aggiornare gli elementi è ancora più semplice (di nuovo, non includere questo codice):

palla [1] = 15;

Dentro void setup (), configurare il display:

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

La prima riga indica alla libreria di Adafruit quali dimensioni e protocollo di comunicazione vengono utilizzati dal display (in questo caso, 128 X 64 e I2C). La seconda linea (Display.Display ()) dice allo schermo di mostrare ciò che è memorizzato nel buffer (che non è nulla).

Creare due metodi chiamati drawBall e 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); 

Questi prendono il X e y coordinate della palla e disegnarla sullo schermo usando il drawCircle metodo dalle librerie di visualizzazione. Questo usa la costante BALL_SIZE definito in precedenza. Prova a cambiare questo e guarda cosa succede. Questo metodo drawCircle accetta un colore pixel - NERO o BIANCA. Poiché questo è un display monocromatico (un colore), il bianco equivale a un pixel acceso e il nero spegne il pixel.

Ora crea un metodo chiamato moveAi:

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

Questo metodo gestisce lo spostamento di Intelligenza artificiale o AI giocatore. Questo è un semplice avversario di computer - Se la palla è sopra la paletta, vai su. È sotto la pagaia, si sposta verso il basso. Abbastanza semplice, ma funziona bene. I simboli di incremento e decremento vengono utilizzati (++aiPos e -aiPos) per aggiungere o sottrarre uno dalla aiPosition. Puoi aggiungere o sottrarre un numero maggiore per far muovere l'IA più velocemente, e quindi essere più difficile da battere. Ecco come lo faresti:

aiPos + = 2;

E:

aiPos - = 2;

Il Più uguale e Meno uguale i segni sono abbreviazioni per aggiungere o sottrarre due da / al valore corrente di aiPos. Ecco un altro modo per farlo:

aiPos = aiPos + 2;

e

aiPos = aiPos - 1;

Si noti come questo metodo prima cancella la paddle e poi la disegna di nuovo. Questo deve essere fatto in questo modo. Se la nuova posizione della paletta è stata disegnata, ci saranno due paddle sovrapposti sullo schermo.

Il DrawNet il metodo usa due anelli per disegnare la rete:

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);  

Questo usa il WALL_WIDTH variabili per impostare la sua dimensione.

Creare metodi chiamati drawPixels e erasePixels. Proprio come i metodi palla, l'unica differenza tra questi due è il colore dei pixel:

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);   

Ancora una volta, entrambi questi metodi ne usano due per loop per disegnare un gruppo di pixel. Piuttosto che dover disegnare ogni pixel usando le librerie drawPixel metodo, i cicli disegnano un gruppo di pixel in base alle dimensioni specificate.

Il drawScore metodo utilizza le funzioni di testo della libreria per scrivere il punteggio giocatore e AI sullo schermo. Questi sono memorizzati in playerScore e aiScore:

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

Questo metodo ha anche un eraseScore controparte, che imposta i pixel su nero o spento.

Gli ultimi quattro metodi sono molto simili. Disegnano e cancellano il giocatore e i 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); cancellaPixel (0, riga + (PADDLE_WIDTH + 2), PADDLE_WIDTH); 

Si noti come chiamano il erasePixel metodo creare prima. Questi metodi disegnano e cancellano la paletta appropriata.

C'è un po 'più di logica nel ciclo principale. Ecco l'intero codice:

#includere  #includere  #includere  #includere  Display Adafruit_SSD1306 (4); int resolution [2] = 128, 64, ball [2] = 20, (risoluzione [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'; booleano inProgress = true; void setup () display.begin (SSD1306_SWITCHCAPVCC, 0x3C); Display.Display ();  void loop () if (aiScore> 9 || playerScore> 9) // verifica lo stato del gioco inProgress = false;  if (inProgress) eraseScore (); cancellaBall (palla [0], palla [1]); if (ballDirectionVerti == 'U') // sposta palla in diagonale palla [1] = palla [1] - VELOCITA ';  if (ballDirectionVerti == 'D') // sposta la palla in diagonale palla [1] = palla [1] + VELOCITÀ;  if (palla [1] <= 0)  // bounce the ball off the top ballDirectionVerti = 'D';  if (ball[1] >= risoluzione [1]) // rimbalza la palla dal fondo pallaDirectionVerti = 'U';  if (ballDirectionHori == 'R') ball [0] = ball [0] + SPEED; // sposta palla se (palla [0]> = (risoluzione [0] - 6)) // palla è sul lato AI dello schermo se ((aiPos + 12)> = palla [1] && (aiPos - 12) <= ball[1])  // ball hits AI paddle if (ball[1] > (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] <= 6)  // ball is at the player edge of the screen if ((playerPos + 12) >= ball [1] && (playerPos - 12) <= ball[1])  // ball hits player paddle if (ball[1] > (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 () // sposta il paddle AIase AIiPaddle (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); 

Ecco cosa ti ritrovi:

Una volta che sei sicuro del codice, ci sono numerose modifiche che puoi apportare:

  • Aggiungi un menu per i livelli di difficoltà (modifica AI e velocità della palla).
  • Aggiungi un movimento casuale alla palla o AI.
  • Aggiungi un altro piatto per due giocatori.
  • Aggiungi un pulsante di pausa.

Ora dai un'occhiata a questi giochi retrò Pi Zero progetti 5 Progetti di gioco retrò con i progetti di gioco retro Raspberry Pi Zero 5 con il Raspberry Pi Zero Il Raspberry Pi Zero ha preso d'assalto il mondo fai-da-te e homebrew, rendendo possibile la revisione di vecchi progetti e ispirando i nuovi arrivati, specialmente nelle menti febbricitanti dei fan dei giochi retrò. Leggi di più .

Hai codificato Pong usando questo codice? Quali modifiche hai apportato? Fatemi sapere nei commenti qui sotto, mi piacerebbe sembrare alcune immagini!

Scopri di più su: Arduino, Elettronica, Retro Gaming.