Arduino Retro Gaming cu un ecran OLED

Arduino Retro Gaming cu un ecran OLED / DIY

V-ați întrebat vreodată cât de mult este nevoie să vă scrieți propriile jocuri retro? Cât de ușor este Pong să cod pentru Arduino? Alăturați-vă cum vă arăt cum să construiți o mini-consola de joc retro cu arduino, și cum să codificați Pong de la zero. Iată rezultatul final:

Construiți un plan

Acesta este un circuit destul de simplu. A potențiometru (pot) va controla jocul, iar un ecran OLED va fi condus de Arduino. Acest lucru va fi produs pe un breadboard, oricum doriți să faceți acest lucru un circuit permanent și să-l instalați într-un caz. Am scris despre recrearea jocului Pong Cum de a recrea jocul clasic de pong Utilizarea lui Arduino Cum să recreezi jocul Pong clasic Folosind Arduino Pong a fost primul joc video care a ajuns pe piața de masă. Pentru prima dată în istorie, conceptul de "joc video" a fost adus în casa familiei, datorită Atari 2600 - ... Citește mai mult înainte, totuși astăzi vă voi arăta cum să scrieți codul de la zero și să rupeți în jos fiecare parte.

De ce ai nevoie

Iată ce aveți nevoie:

  • 1 x Arduino (orice model)
  • 1 x 10k Potențiometru
  • 1 x display OLED de 0,92 "
  • 1 x Breadboard
  • Asortați bărbați> fire de cuplu de sex masculin

DIYmall 0.96 "Inch I2c IIC Serial 128x64 Oled LCD LED Modul alb de afișare pentru Arduino 51 Msp420 Stim32 SCR DIYmall 0.96" Inch I2c IIC Serial 128x64 Oled LCD LED Modul alb Afișaj pentru Arduino 51 Msp420 Stim32 SCR Cumpara acum la Amazon $ 8.99

Orice Arduino ar trebui să funcționeze, așa că uita-te la ghidul nostru de cumpărare Arduino Ghid de cumpărare: Care ar trebui să obțineți? Arduino Ghidul de cumpărare: care ar trebui să obțineți? Există atât de multe feluri de plăci de arduino, acolo vei fi iertat că ești confuz. Care ar trebui să cumpărați pentru proiectul dvs.? Să ne ajute, cu acest ghid de cumpărare Arduino! Citiți mai multe dacă nu sunteți sigur ce model să cumpărați.

Aceste display-uri OLED sunt foarte cool. Ele pot fi de obicei achiziționate în alb, albastru, galben sau un amestec al celor trei. Ele există în culori pline, cu toate acestea acestea adaugă un întreg alt nivel complexității și costului acestui proiect.

Circuitul

Acesta este un circuit simplu. Dacă nu aveți prea multă experiență cu Arduino, verificați aceste proiecte începători 15 Proiecte Great Arduino pentru începători 15 Proiecte excelente Arduino pentru începători Interesați de Arduino dar nu sunteți sigur de unde să începeți? Iată câteva dintre cele mai bune proiecte Arduino pentru începători pentru a începe! Mai întâi citiți mai multe.

Aici este:

Privind la partea din față a vasului, conectați pinul din stânga la +5V și pinul drept la sol. Conectați pinul de mijloc la pinul analogic 0 (A0).

Afișajul OLED este conectat utilizând protocolul I2C. Conectați VCC și GND la Arduino +5V și sol. Conectați SCL la analog cinci (A5). Conectați SDA la analog 4 (A4). Motivul pentru care este conectat la pinii analogici este simplu; aceste pini conțin circuitele necesare pentru protocolul I2C. Asigurați-vă că acestea sunt conectate corect și nu sunt traversate. Pinii exacti vor varia în funcție de model, dar A4 și A5 sunt utilizați pe Nano și Uno. Verificați documentația bibliotecii Wire pentru modelul dvs. dacă nu utilizați un dispozitiv Arduino sau Nano.

Pot test

Încărcați acest cod de test (asigurați-vă că ați selectat placa și portul corect din Unelte > Bord și Unelte > Port meniuri):

void setup () // pune codul de instalare aici, pentru a rula o singură dată: Serial.begin (9600); // set serial void loop () // introduceți aici codul principal, pentru a rula în mod repetat: Serial.println (analogRead (A0)); // tipăriți valoarea din întârziere (500); 

Deschideți acum monitorul serial (Sus în dreapta > Monitor serial) și rotiți vasul. Ar trebui să vedeți valoarea afișată pe monitorul serial. Ar trebui să fie complet contra-sensul acelor de ceasornic zero, și ar trebui să fie complet în sensul acelor de ceasornic 1023:

Veți regla acest lucru mai târziu, dar deocamdată este bine. Dacă nu se întâmplă nimic sau valoarea se modifică fără să faceți nimic, deconectați și verificați dublu circuitul.

Test OLED

Ecranul OLED este ușor mai complex pentru configurare. Trebuie să instalați două biblioteci pentru a afișa primul ecran. Descărcați bibliotecile Adafruit_SSD1306 și Adafruit-GFX de la Github. Copiați fișierele în folderul bibliotecilor. Acest lucru variază în funcție de sistemul dvs. de operare:

  • Mac OS: / Users / utilizator / Documente / Arduino / biblioteci
  • Linux: / Home / username / Sketchbook
  • ferestre: / Users / Arduino / biblioteci

Încărcați acum o schiță de testare. Mergi la Fişier > Exemple > Adafruit SSD1306 > ssd1306_128x64_i2c. Acest lucru vă va oferi o schiță mare care conține o mulțime de elemente grafice:

Dacă după încărcare nu se întâmplă nimic, deconectați și verificați dublu conexiunile. Dacă exemplele nu sunt în meniuri, este posibil să fie nevoie să reporniți ID-ul Arduino.

Codul

Acum este timpul pentru cod. Voi explica fiecare pas, așa că treceți până la capăt dacă doriți doar să îl rulați. Aceasta este o sumă corectă a codului, deci dacă nu vă simțiți încrezători, verificați aceste 10 resurse gratuite Aflați la cod: 10 Resurse online gratuite și fantastice pentru a vă perfecționa abilitățile Aflați cum să codificați: 10 resurse gratuite și fantastice online pentru a vă perfecționa Codificarea competențelor. Un subiect care este evitat de mulți. Există o abundență de resurse și instrumente gratuite, toate fiind disponibile online. Sigur că ați putea lua câteva cursuri pe această temă la un ... Read More pentru a învăța să codificați.

Începeți prin includerea bibliotecilor necesare:

#include  #include  #include  #include 

SPI și SÂRMĂ sunt două biblioteci Arduino pentru manipularea comunicării I2C. Adafruit_GFX și Adafruit_SSD1306 sunt bibliotecile instalate anterior.

Apoi, configurați afișajul:

Afișajul Adafruit_SSD1306 (4);

Apoi configurați toate variabilele necesare pentru a rula jocul:

int rezoluție [2] = 128, 64, minge [2] = 20, (rezoluție [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', bilaDirectionVerti = 'S'; boolean inProgress = adevărat;

Acestea stochează toate datele necesare pentru a rula jocul. Unele dintre acestea stochează locația mingii, dimensiunea ecranului, locația jucătorului și așa mai departe. Observați cum sunt unele dintre acestea const ceea ce înseamnă că acestea sunt constante și nu se vor schimba niciodată. Aceasta permite vitezei compilatorului Arduino să facă ceva.

Rezoluția ecranului și locația mingii sunt stocate în matrice. Arrays sunt colecții de lucruri similare, iar pentru minge, stocați coordonatele (X și Y). Accesarea elementelor din matrice este ușoară (nu includeți acest cod în fișierul dvs.):

Rezoluția [1];

Pe măsură ce matricele încep de la zero, acest lucru va returna al doilea element din matricea de rezoluție (64). Actualizarea elementelor este chiar mai ușoară (din nou, nu includeți acest cod):

bila [1] = 15;

Interior void setup (), configurați afișajul:

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

Prima linie spune bibliotecii Adafruit care sunt dimensiunile și protocolul de comunicații pe care afișează afișajul dvs. (în acest caz, 128 X 64 și I2C). Al doilea rând (display.display ()) spune ecranului să arate ce este stocat în tampon (care nu este nimic).

Creați două metode numite drawBall și eraseBall:

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

Acestea iau X și y coordonatele mingii și trageți-o pe ecran folosind drawCircle din bibliotecile de afișare. Aceasta folosește constanta BALL_SIZE definit mai devreme. Încercați să modificați acest lucru și să vedeți ce se întâmplă. Această metodă drawCircle acceptă o culoare pixel - NEGRU sau ALB. Deoarece acesta este un afișaj monocromatic (o singură culoare), albul este egal cu un pixel care este activat și negrul face pixelul oprit.

Acum creați o metodă numită moveAi:

void moveAi () eraseAiPaddle (aiPos); dacă (minge [1]> aiPos) ++ aiPos;  altfel dacă [minge [1] < aiPos)  --aiPos;  drawAiPaddle(aiPos); 

Această metodă gestionează mișcarea Inteligență artificială sau AI jucător. Acesta este un adversar simplu de calculator - Dacă mingea este deasupra paletei, deplasați-vă în sus. Acesta este sub paleta, se deplasează în jos. Destul de simplu, dar funcționează bine. Sunt utilizate simbolurile incrementării și decrementării (++aiPos și -aiPos) pentru a adăuga sau a scădea unul din indexul aiPosition. Puteți adăuga sau scădea un număr mai mare pentru a face AI să se deplaseze mai repede și, prin urmare, să fie mai greu de învins. Iată cum ați face acest lucru:

aiPos + = 2;

Și:

aiPos - = 2;

Plus egal și Minus Equals semnele sunt scurte pentru adăugarea sau scăderea a două de la / la valoarea curentă a aiPos. Iată un alt mod de a face acest lucru:

aiPos = aiPos + 2;

și

aiPos = aiPos-1;

Observați cum această metodă șterge mai întâi paleta și apoi o trage din nou. Acest lucru trebuie făcut așa. Dacă noua poziție a paletei a fost desenată, pe ecran vor exista două paduri suprapuse.

drawNet metoda utilizează două bucle pentru a trage net:

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

Aceasta utilizează WALL_WIDTH variabile pentru a seta dimensiunea acesteia.

Creați metode numite drawPixels și erasePixels. La fel ca metodele mingii, singura diferență dintre acestea este culoarea pixelilor:

void drawPixel (int posX, int posY, int dimensiuni) pentru (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);   

Din nou, ambele metode utilizează două pentru pentru a desena un grup de pixeli. Mai degrabă decât a fi nevoie să desenezi fiecare pixel folosind bibliotecile drawPixel , buclele trasează un grup de pixeli pe baza dimensiunilor date.

drawScore metoda utilizează caracteristicile textului bibliotecii pentru a scrie pe ecran playerul și scorul AI. Acestea sunt stocate în playerScore și aiScore:

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

Această metodă are, de asemenea, eraseScore omolog, care stabilește pixeli negru sau oprit.

Cele patru metode finale sunt foarte asemănătoare. Ei trag și șterg jucătorul și padelele AI:

void erasePlayerPaddle (rândul int) erasePixel (0, rând - (PADDLE_WIDTH * 2), PADDLE_WIDTH); erasePixel (0, rând - PADDLE_WIDTH, PADDLE_WIDTH); erasePixel (0, rând, PADDLE_WIDTH); erasePixel (0, rând + PADDLE_WIDTH, PADDLE_WIDTH); erasePixel (0, rând + (PADDLE_WIDTH + 2), PADDLE_WIDTH); 

Observați cum se numește erasePixel metoda de creare mai devreme. Aceste metode trage și șterge paleta potrivită.

Există un pic mai multă logică în bucla principală. Iată întregul cod:

#include  #include  #include  #include  Afișajul Adafruit_SSD1306 (4); int rezoluție [2] = 128, 64, minge [2] = 20, (rezoluție [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', bilaDirectionVerti = 'S'; boolean inProgress = adevărat; void setup () display.begin (SSD1306_SWITCHCAPVCC, 0x3C); display.display ();  void loop () if (aiScore> 9 || playerScore> 9) // verificați starea jocului înProgress = false;  dacă (inProgress) eraseScore (); eraseBall (minge [0], minge [1]); dacă (ballDirectionVerti == 'U') // mutați mingea în diagonală minge [1] = minge [1] - SPEED;  în cazul în care (ballDirectionVerti == 'D') / muta bila mingea în diagonală [1] = minge [1] + SPEED;  dacă (minge [1] <= 0)  // bounce the ball off the top ballDirectionVerti = 'D';  if (ball[1] >= rezoluție [1]) // bounce mingea de jos ballDirectionVerti = 'U';  dacă (ballDirectionHori == 'R') minge [0] = minge [0] + SPEED; / / minge [1] && (aiPos - 12) / = minge [1] && (aiPos - 12) <= ball[1])  // ball hits AI paddle if (ball[1] > (aiPos + 4)) // deflectează mingea în jos ballDirectionVerti = 'D';  altfel dacă [minge [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) >= minge [1] && (jucătoriPos - 12) <= ball[1])  // ball hits player paddle if (ball[1] > (playerPos + 4)) // deflectează mingea în jos ballDirectionVerti = 'D';  altfel dacă [minge [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 ("TREBUIE LUAT!");  altfel dacă (playerScore> aiScore) display.println ("YOU WIN!");  display.display ();  void moveAi () // mutați paleta AI eraseAiPaddle (aiPos); dacă (minge [1]> aiPos) ++ aiPos;  altfel dacă [minge [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); 

Iată ce faceți cu dvs.:

Odată ce sunteți încrezători în cod, există numeroase modificări pe care le puteți face:

  • Adăugați un meniu pentru nivelurile de dificultate (modificați AI și viteza mingii).
  • Adăugați o mișcare aleatorie la minge sau AI.
  • Adăugați un alt pot pentru doi jucători.
  • Adăugați un buton de pauză.

Acum, aruncăm o privire la aceste proiecte de joc Pi Zero retro 5 Proiecte de jocuri retro cu zmeura Pi Zero 5 Proiecte de jocuri retro cu zmeura Pi Zero Zmeura Pi Zero a preluat lumea de bricolaj și homebrew, făcând posibilă revizuirea proiectelor vechi și inspirând noii veniți, mai ales în mintea febrilă a fanilor retro gaming. Citeste mai mult .

Ați codat Pong utilizând acest cod? Ce modificări ați făcut? Dați-mi voie să știu în comentariile de mai jos, mi-ar plăcea să par niște poze!

Explorați mai multe despre: Arduino, Electronică, Jocuri retro.