Arduino Retro Gaming Med OLED-skjerm
Noen gang lurt på hvor mye arbeid det tar å skrive dine egne retrospill? Hvor lett er Pong å kode for Arduino? Bli med meg da jeg viser deg hvordan du bygger en Arduino-drevet mini retro spillkonsoll, og hvordan du kodes Pong fra bunnen av. Her er sluttresultatet:
Bygg Plan
Dette er en ganske enkel krets. EN potensiometer (pott) vil styre spillet, og en OLED-skjerm vil bli drevet av Arduino. Dette vil bli produsert på et brettbrett, men du kan ønske å gjøre dette til en permanent krets og installere den i et tilfelle. Vi har skrevet om å gjenskape Pong Slik gjenoppretter du det klassiske Pong-spillet Bruke Arduino Slik gjenoppretter du det klassiske Pong-spillet Bruke Arduino Pong var det første noensinne videospillet som nådde massemarkedet. For første gang i historien ble konseptet med et "videospill" brakt inn i familiens hjem, takket være Atari 2600 - ... Les mer før, men i dag vil jeg vise deg hvordan du skriver koden fra bunnen av og bryter ned hver del.
Hva trenger du
Her er hva du trenger:
- 1 x Arduino (hvilken som helst modell)
- 1 x 10k Potentiometer
- 1 x 0,96 "I2C OLED Display
- 1 x brødbrett
- Assortert mann> mannlige hookup ledninger
DIYmall 0.96 "Inch I2c IIC Seriell 128x64 Oled LCD LED Hvit Display Modul for Arduino 51 Msp420 Stim32 SCR DIYmall 0.96" Inch I2c IIC Seriell 128x64 Oled LCD LED Hvit Display Modul for Arduino 51 Msp420 Stim32 SCR Kjøp nå på Amazon $ 8.99
Eventuelle Arduino bør jobbe, så se på vår kjøpeguide Arduino Kjøpsguide: Hvilket styre bør du få? Arduino Kjøpsguide: Hvilket styre bør du få? Det er så mange forskjellige typer Arduino boards der ute, du vil bli tilgitt for å være forvirret. Hvilken bør du kjøpe for prosjektet ditt? La oss hjelpe, med denne Arduino kjøpesiden! Les mer hvis du ikke er sikker på hvilken modell du skal kjøpe.
Disse OLED-skjermene er veldig kule. De kan vanligvis kjøpes i hvitt, blått, gult eller en blanding av de tre. De eksisterer i full farge, men disse legger et helt annet nivå til kompleksiteten og kostnaden av dette prosjektet.
Kredsløpet
Dette er en ganske enkel krets. Hvis du ikke har mye erfaring med Arduino, sjekk ut disse nybegynnerprosjektene 15 Great Arduino-prosjekter for nybegynnere 15 Great Arduino-prosjekter for nybegynnere Interessert i Arduino, men ikke sikker på hvor du skal begynne? Her er noen av våre beste Arduino-prosjekter for nybegynnere å komme i gang med! Les mer først.
Her er det:
Når du ser på forsiden av potten, kobler du venstre stolpe til +5V og den rette pinnen til bakke. Koble midtpinnen til analog pin 0 (A0).
OLED-skjermen er koblet til ved hjelp av I2C-protokollen. Koble VCC og GND til Arduino +5V og bakke. Koble SCL til analog fem (A5). Koble SDA til analog 4 (A4). Grunnen til at dette er koblet til de analoge pinnene er enkelt; Disse pinnene inneholder kretsene som kreves for I2C-protokollen. Kontroller at disse er koblet riktig, og ikke krysset over. De eksakte pinnene vil variere etter modell, men A4 og A5 brukes på Nano og Uno. Sjekk Wirebibliotekets dokumentasjon for din modell hvis du ikke bruker en Arduino eller Nano.
Pot Test
Last opp denne testkoden (pass på at du velger riktig kort og port fra Verktøy > Borde og Verktøy > Havn menyer):
ugyldig oppsett () // sett opp konfigurasjonskoden din her, for å kjøre en gang: Serial.begin (9600); // setup serial void loop () // sett hovedkoden her, for å kjøre gjentatte ganger: Serial.println (analogRead (A0)); // skriv ut verdien fra potten forsinkelsen (500);
Åpne nå seriell skjerm (Øverst til høyre > Seriell skjerm) og skru pannen. Du bør se verdien som vises på seriell skjerm. Helt mot klokka bør være null, og helt med klokken bør være 1023:
Du vil justere dette senere, men for nå er det greit. Hvis ingenting skjer, eller verdien endres uten at du gjør noe, koble fra og dobbeltkoble kretsen.
OLED Test
OLED-skjermen er litt kompleksere å konfigurere. Du må installere to biblioteker for å kjøre skjermen først. Last ned Adafruit_SSD1306 og Adafruit-GFX biblioteker fra Github. Kopier filene til bibliotekets mappe. Dette varierer avhengig av operativsystemet ditt:
- Mac os: / Users / brukernavn / Dokumenter / Arduino / bibliotek
- Linux: / Home / brukernavn / skissebok
- Windows: / Brukere / Arduino / bibliotek
Last opp en testskisse. Gå til Fil > eksempler > Adafruit SSD1306 > ssd1306_128x64_i2c. Dette bør gi deg en stor skisse som inneholder mye grafikk:
Hvis ingenting skjer etter opplasting, koble fra og dobbeltkoble tilkoblingene. Hvis eksemplene ikke er i menyene, må du kanskje starte din Arduino IDE på nytt.
Koden
Nå er det tid for koden. Jeg skal forklare hvert trinn, så hopp over til slutten hvis du bare vil få det til å løpe. Dette er en god del kode, så hvis du ikke føler deg trygg, sjekk ut disse 10 gratis ressursene. Lær å kode: 10 gratis og fantastiske elektroniske ressurser for å finpusse dine ferdigheter. Lær å kode: 10 gratis og fantastiske elektroniske ressurser for å finpusse Ferdighetskoding. Et emne som unngås av mange. Det finnes en overflod av gratis ressurser og verktøy, som alle er tilgjengelige online. Sikker på at du kan ta noen kurs på emnet på en nærliggende ... Les mer for å lære å kode.
Begynn med å inkludere de nødvendige bibliotekene:
#inkludere #inkludere #inkludere #inkludere
SPI og METALLTRÅD er to Arduino-biblioteker for håndtering av I2C-kommunikasjonen. Adafruit_GFX og Adafruit_SSD1306 er bibliotekene du installerte tidligere.
Deretter konfigurer skjermen:
Adafruit_SSD1306 display (4);
Sett deretter opp alle variablene som trengs for å kjøre spillet:
int oppløsning [2] = 128, 64, ball [2] = 20, (oppløsning [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;
Disse lagrer alle dataene som er nødvendige for å kjøre spillet. Noen av disse lagrer plasseringen av ballen, størrelsen på skjermen, plasseringen av spilleren og så videre. Legg merke til hvordan noen av disse er konst noe som betyr at de er konstante, og vil aldri forandre seg. Dette gjør at Arduino-kompilatoren raskerer opp ting.
Skjermoppløsningen og ballplasseringen er lagret i arrays. Arrays er samlinger av lignende ting, og for ballen, lagre koordinatene (X og Y). Å få tilgang til elementer i arrays er enkelt (ikke inkluder denne koden i filen din):
oppløsning [1];
Når arrayene starter ved null, returnerer dette det andre elementet i oppløsningsarmen (64). Oppdatere elementer er enda enklere (igjen, ikke inkluder denne koden):
ball [1] = 15;
Innsiden ugyldig oppsett (), konfigurer skjermen:
tomromoppsett () display.begin (SSD1306_SWITCHCAPVCC, 0x3C); display.display ();
Den første linjen forteller Adafruit-biblioteket hvilke dimensjoner og kommunikasjonsprotokoll skjermen din bruker (i dette tilfellet, 128 x 64 og I2C). Den andre linjen (display.display ()) forteller skjermen for å vise hva som er lagret i bufferen (som ikke er noe).
Lag to metoder kalt drawBall og 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);
Disse tar x og y koordinater av ballen og tegne den på skjermen ved hjelp av drawcircle metode fra displaybibliotekene. Dette bruker konstanten BALL_SIZE definert tidligere. Prøv å endre dette og se hva som skjer. Denne drawCircle-metoden aksepterer en pikselfarge - SVART eller HVIT. Siden dette er en monokromatisk skjerm (en farge), står hvit til en piksel som er på, og svart svinger pikselet av.
Opprett nå en metode som kalles moveAi:
void moveAi () eraseAiPaddle (aiPos); hvis (ball [1]> aiPos) ++ aiPos; annet hvis (ball [1] < aiPos) --aiPos; drawAiPaddle(aiPos);
Denne metoden håndterer å flytte Kunstig intelligens eller AI spiller. Dette er en ganske enkel datamaskin motstander - Hvis ballen er over padleen, flytter du opp. Den er under padleen, flytt ned. Ganske enkelt, men det fungerer bra. Inkrement- og dekningssymbolene blir brukt (++aiPos og -aiPos) for å legge til eller trekke en fra aiPositionen. Du kan legge til eller trekke et større tall for å få AI til å bevege seg raskere, og derfor være vanskeligere å slå. Slik gjør du det:
aiPos + = 2;
Og:
aiPos - = 2;
De Plus er lik og Minus er lik tegn er stenografi for å legge til eller trekke to fra / til dagens verdi av aiPos. Her er en annen måte å gjøre det på:
aiPos = aiPos + 2;
og
aiPos = aiPos - 1;
Legg merke til hvordan denne metoden først sletter padlen, og trekker den deretter igjen. Dette må gjøres slik. Hvis den nye posisjonen til padlen ble trukket, ville det være to overlappende padler på skjermen.
De drawNet Metoden bruker to løkker for å tegne nettet:
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);
Dette bruker WALL_WIDTH variabler for å angi størrelsen.
Opprett metoder kalt drawPixels og erasePixels. Akkurat som ballen, er den eneste forskjellen mellom disse to fargene på pikslene:
void drawPixel (int posX, int posY, int dimensjoner) 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);
Igjen, begge disse metodene bruker to til sløyfer for å tegne en gruppe piksler. Snarere enn å måtte tegne hver piksel ved hjelp av bibliotekene drawPixel Metoden, løkkene tegner en gruppe piksler basert på de oppgitte dimensjonene.
De drawScore Metoden bruker tekstfunksjonene i biblioteket til å skrive spilleren og AI-score til skjermen. Disse er lagret i playerScore og aiScore:
void drawScore () display.setTextSize (2); display.setTextColor (hvit); display.setCursor (45, 0); display.println (playerScore); display.setCursor (75, 0); display.println (aiScore);
Denne metoden har også a eraseScore motpart, som setter piksler til svart eller av.
De siste fire metodene er veldig like. De tegner og sletter spilleren og AI padler:
void erasePlayerPaddle (int rad) erasePixel (0, rad - (PADDLE_WIDTH * 2), PADDLE_WIDTH); erasePixel (0, rad - PADDLE_WIDTH, PADDLE_WIDTH); erasePixel (0, rad, PADDLE_WIDTH); erasePixel (0, rad + PADDLE_WIDTH, PADDLE_WIDTH); erasePixel (0, rad + (PADDLE_WIDTH + 2), PADDLE_WIDTH);
Legg merke til hvordan de kaller erasePixel Metoden skaper tidligere. Disse metodene tegner og sletter riktig padle.
Det er litt mer logikk i hovedløkken. Her er hele koden:
#inkludere #inkludere #inkludere #inkludere Adafruit_SSD1306 display (4); int oppløsning [2] = 128, 64, ball [2] = 20, (oppløsning [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; tomromoppsett () display.begin (SSD1306_SWITCHCAPVCC, 0x3C); display.display (); tomgangsløype () hvis (aiScore> 9 || playerScore> 9) // sjekk spilltilstand inProgress = false; hvis (inProgress) eraseScore (); eraseBall (ball [0], ball [1]); hvis (ballDirectionVerti == 'U') // flytte ballen opp diagonalt ball [1] = ball [1] - SPEED; hvis (ballDirectionVerti == 'D') // flytte ballen ned diagonalt ball [1] = ball [1] + SPEED; hvis (ball [1] <= 0) // bounce the ball off the top ballDirectionVerti = 'D'; if (ball[1] >= oppløsning [1]) // sprette ballen fra bunnen ballDirectionVerti = 'U'; hvis (ballDirectionHori == 'R') ball [0] = ball [0] + SPEED; // flytte ballen hvis (ball [0]> = (oppløsning [0] - 6)) // ball er ved AI-kanten av skjermen hvis ((aiPos + 12)> = ball [1] && (aiPos - 12) <= ball[1]) // ball hits AI paddle if (ball[1] > (aiPos + 4)) // avbøy ball ned ballDirectionVerti = 'D'; annet hvis (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)) // avbøy ball ned ballDirectionVerti = 'D'; annet hvis (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!"); annet hvis (playerScore> aiScore) display.println ("DU VIN!"); display.display (); void moveAi () // flytte AI padle eraseAiPaddle (aiPos); hvis (ball [1]> aiPos) ++ aiPos; annet hvis (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);
Her er hva du ender med:
Når du er trygg på koden, er det mange modifikasjoner du kan gjøre:
- Legg til en meny for vanskelighetsnivåer (endre AI og ballhastighet).
- Legg til litt tilfeldig bevegelse til ballen eller AI.
- Legg til en annen pott for to spillere.
- Legg til en pause-knapp.
Ta en titt på disse retro spillene Pi Zero-prosjekter 5 Retro Gaming-prosjekter med Raspberry Pi Zero 5 Retro Gaming-prosjekter med Raspberry Pi Zero Raspberry Pi Zero har tatt DIY og homebrew verden med storm, noe som gjør det mulig å revidere gamle prosjekter og inspirerende nykommere, spesielt i de feberte hjernene til retrospillere. Les mer .
Har du kodet Pong ved hjelp av denne koden? Hvilke modifikasjoner gjorde du? Gi meg beskjed i kommentarene nedenfor, jeg vil gjerne se noen bilder!
Utforsk mer om: Arduino, Elektronikk, Retro Gaming.