Innehållsförteckning:

Arduino OLED Snake Game: 3 steg
Arduino OLED Snake Game: 3 steg

Video: Arduino OLED Snake Game: 3 steg

Video: Arduino OLED Snake Game: 3 steg
Video: Arduino Snake Game on an OLED display. 2024, Juli
Anonim
Arduino OLED Snake Game
Arduino OLED Snake Game

Hej och välkommen, till våra instruktioner om hur man gör och arduino OLED -spel, detta projekt kom till när vi försökte göra vårt första spel någonsin med en arduino, soooo, vi tänkte var bättre att börja än nokia classic Snake (väl kl. minst en ormklon:)).

Vad du kommer att behöva

Tillbehör

Arduino UNO eller klon

OLED -skärm

4 dioder

500-1k motstånd

4 kontrollknappar

Passiv Piezo -summer

frivillig

Lödfritt brödbräda

Observera att dessa länkar endast är till exempel

Steg 1: Kretsen

Kretsen
Kretsen

På bilden ovan kan du se vår krets, vi använder stift d3 på arduino som en avbrottsförfrågan stift så att arduino kommer att prioritera läsning av styringångarna som är d4 d5 d6 d7. Grunderna i kretsen är att man trycker på en riktningsknapp som går högt 5v detta aktiverar avbrottsbegäran (d3 lila tråd) och en motsvarande riktningstapp, avbrottsfunktionen kallar en uppdateringsriktningsfunktion och den koden flyttar ormen i enlighet därmed. Stift 9 används som ljudstift eftersom det är en PWM (~ pulsbreddsmodulering) som är direkt ansluten till en 5v piezo på + stiftet och - går tillbaka till 0v/mark.

(FYI på arduino uno och kloner endast d2 och d3 kan fungera som avbrott begäran stift).

Riktningsstift:

d4 Upp ORANGE

d5 NED ROSA

d6 Vänster BLÅ

d7 Höger BRUN

d9 ljud GRÅ

Varje knapp har en in 5v anslutningsingång och en utgång som först är ansluten till sin respektive digitala ingång på arduino, samma utgång för varje knapp ansluts sedan till sin egen diod, vi använder dioderna för att stoppa spänningen som matas tillbaka till andra knappar och aktivera dem. På katod (-) änden av alla 4 dioder sammanfogar vi dem för att skapa en utgångskoppling som ansluts till d3 och sedan genom a-motståndet till 0v/jord för att dra arduino-stiften lågt för att inte lämna flytande stift när de inte är aktiverad.

(FYI en flytande stift kan ta emot fantomspänning och orsaka ovanligt beteende)

2 analoga stift används för att driva bildskärmen, det här är arduino hardware i2c -stiften.

A5 är ansluten till SCL GUL

A4 är ansluten till SDA GREEN

+5v och 0v (jord) utgången från arduino används som energikälla för hela kretsen som kan drivas av usb eller telefonladdare.

Steg 2: Koden

// ------------------------ ANJAWARE SNAKE-spel Med hjälp från nätets folk --------------- -------

#omfatta

#include // https://github.com/adafruit/Adafruit-GFX-Library #include // https://github.com/adafruit/Adafruit-GFX-Library // display set (width, height) Adafruit_SSD1306 display (128, 64); // definiera ingångsstiften det här är stiften på arduino de ändras aldrig så #define #define INTPIN 3 // endast stift 2 och 3 kan vara avbrottsstift på UNO #define UPPIN 4 // dessa är stift anslutna tp relevant switch #define DWNPIN 5 #define LFTPIN 6 #define RHTPIN 7 #define SND 9 // definiera riktningar #define DIRUP 1 // dessa värden är vad "ormen" tittar på för att bestämma- #define DIRDOWN 2 // riktningen ormen kommer att färdas # definiera DIRLEFT 3 #define DIRRIGHT 4

// ange knappvariabler

// volitile cos vi behöver den för att uppdatera med avbrottet så kan vara vilken som helst cykelvärde

// är aldrig högre än 4 så behöver bara 8bit int för att spara resurser flyktiga uint8_t buttonpressed = 0; bool butup = 0; bool butdown = 0; // vi använder detta för att ställa in true för att "upptäcka" vilken riktning som tryckts bool butleft = 0; bool butright = 0;

// orm ints

byte snakePosX [30]; // array för att göra kroppen av ormbyte snakePosY [30];

int snakeX = 30; // ormhuvudets position

int ormY = 30; int snakeSize = 1; // ormstorleksantal begränsat till matrisens storlek

// world ints

uint8_t worldMinX = 0; // dessa sätter gränserna för spelområdet

uint8_t worldMaxX = 128; uint8_t worldMinY = 10; uint8_t worldMaxY = 63;

// samla scran (mat) och position för scran

bool scranAte = 0; uint8_t scranPosX = 0; uint8_t scranPosY = 0;

// poängsätter variabler

lång spelpoäng = 0; lång poäng = 30; // sätta hög poäng till 3 samla som utgångspunkt

// --------------------------- detta är vad interuptet utför vid spänningsökning ------------ -------------

void interruptpressed () {delay (150); // lätt fördröjning för extra "studs" skydd uppdaterad riktning (); } // ------------------ uppdatera riktningsvärdet från knapptryckning ----------------- void updatedirection () { // Serial.println ("updatingdirection"); butup = digitalRead (UPPIN); // kontrollera vilken ingång som gick högt och ställ in relevant bool true butdown = digitalRead (DWNPIN); butleft = digitalRead (LFTPIN); butright = digitalRead (RHTPIN); // dessa om statemeenter tittar på vilken ingång som gick högt och anger det relevanta värdet i "knapptryckt" // variabel, denna variabel dikterar rörelseriktningen om (butup == true) {buttonpressed = DIRUP; // Serial.println ("UPP tryckt"); // Serial.println (knapptryckt); butup = falskt; ton (SND, 1500, 10); } if (butdown == true) {buttonpressed = DIRDOWN; // Serial.println ("NER tryckt"); // Serial.println (knapptryckt); butdown = false; ton (SND, 1500, 10); }

om (butleft == true)

{buttonpressed = DIRLEFT; // Serial.println ("VÄNSTER nedtryckt"); // Serial.println (knapptryckt); butleft = falskt; ton (SND, 1500, 10); } if (butright == true) {buttonpressed = DIRRIGHT; // Serial.println ("HÖGER tryckt"); // Serial.println (knapptryckt); butright = falskt; ton (SND, 1500, 10); }}

// -------------------------- rita visningsrutinerna ------------------ -----------------

void updateDisplay () // rita poäng och konturer

{// Serial.println ("Uppdateringsvisning");

display.fillRect (0, 0, display.width ()-1, 8, SVART);

display.setTextSize (0); display.setTextColor (VIT); // draw scores display.setCursor (2, 1); display.print ("Poäng:"); display.print (String (playscore, DEC)); display.setCursor (66, 1); display.print ("Hög:"); display.print (String (highscore, DEC)); // rita spelområde // pos 1x, 1y, 2x, 2y, färgdisplay.drawLine (0, 0, 127, 0, WHITE); // mycket övre kantdisplay.drawLine (63, 0, 63, 9, VIT); // poängseparator display.drawLine (0, 9, 127, 9, WHITE); // under textgränsen display.drawLine (0, 63, 127, 63, WHITE); // nedre gränsen display.drawLine (0, 0, 0, 63, WHITE); // vänster kantdisplay.drawLine (127, 0, 127, 63, WHITE); // höger kant

}

// ----------------------------------- uppdatera uppspelningsområdet ---------- --------------------

void updateGame () // detta uppdaterar spelområdet

{display.clearDisplay ();

display.drawPixel (scranPosX, scranPosY, WHITE);

scranAte = scranFood ();

// kolla ormrutiner

if (outOfArea () || selfCollision ())

{gameOver (); }

// visa orm

för (int i = 0; i0; i--) {snakePosX = snakePosX [i-1]; snakePosY = snakePosY [i-1]; } // lägg till en extra pixel i ormen if (scranAte) {snakeSize+= 1; snakePosX [snakeSize-1] = snakeX; snakePosY [snakeSize-1] = ormY; }

switch (knapptryckt) // var snakeDirection

{fall DIRUP: snakeY- = 1; ha sönder; fall DIRDOWN: snakeY+= 1; ha sönder; fall DIRLEFT: snakeX- = 1; ha sönder; fall DIRRIGHT: snakeX+= 1; ha sönder; } snakePosX [0] = snakeX; snakePosY [0] = ormY; updateDisplay (); display.display (); // --------------------- placera scranen -------------------

void placeScran ()

{scranPosX = random (worldMinX+1, worldMaxX-1); scranPosY = random (worldMinY+1, worldMaxY-1); } // ------------------------ SCRAN ATE POINT UP ---------------- bool scranMat () {if (snakeX == scranPosX && snakeY == scranPosY) {playscore = playscore+10; ton (SND, 2000, 10); updateDisplay (); placeScran (); retur 1; } annat {return 0; }} // --------------------- utanför området ---------------------- bool outOfArea () {return snakeX = worldMaxX || snakeY = worldMaxY; } // ---------------------- spelet är över ----------------------- --- void gameOver () {uint8_t rectX1, rectY1, rectX2, rectY2; rectXl = 38; rectY1 = 28; rectX2 = 58; rectY2 = 12; display.clearDisplay (); display.setCursor (40, 30); display.setTextSize (1); ton (SND, 2000, 50); display.print ("GAME"); ton (SND, 1000, 50); display.print ("OVER"); if (playscore> = highscore) // kolla om poängen är högre än high score {highscore = playscore; // single if statment to update high score} för (int i = 0; i <= 16; i ++) // detta är att rita rektanglar runt spelet över {display.drawRect (rectX1, rectY1, rectX2, rectY2, WHITE); Serial.println ("if loop"); display.display (); rectX1- = 2; // skifta med 2 pixlar rectY1- = 2; rectX2+= 4; // skifta över 2 pixlar från sista punkten rectY2+= 4; ton (SND, i*200, 3); } display.display (); // Skärmtorkning efter berömmelse över rectX1 = 0; // ange startposition för rad rectY1 = 0; rectX2 = 0; rectY2 = 63; för (int i = 0; i <= 127; i ++) {uint8_t cnt = 0; display.drawLine (rectX1, rectY1, rectX2, rectY2, SVART); rectX1 ++; rectX2 ++; display.display (); } display.clearDisplay (); playcore = 0; // återställ orm- och spelardetaljer snakeSize = 1; snakeX = display.width ()/2; ormY = display.height ()/2; waitForPress (); // vänta på att spelaren ska starta spelet} // ------------------------- vänta på tryckningsslinga ---------- --------------- void waitForPress () {bool waiting = 0; // loop slutar när detta är sant display.clearDisplay (); medan (väntar == 0) {drawALineForMe (VIT); // rita en slumpmässig vit linje drawALineForMe (SVART); // rita en slumpmässig svart linje så att skärmen inte helt fyller vit display.fillRect (19, 20, 90, 32, SVART); // tom bakgrund för textvisning.setTextColor (VIT); display.setCursor (35, 25); display.setTextSize (2); // större teckensnitt display.println ("SNAKE"); // x y w h r col display.drawRoundRect (33, 22, 62, 20, 4, WHITE); // border Snake display.drawRect (19, 20, 90, 32, WHITE); // kantlåda - 3 display.setCursor (28, 42); display.setTextSize (0); // font tillbaka till normal display.println ("tryck på valfri knapp"); display.display (); väntar = digitalRead (INTPIN); // kontrollera om tangenten trycks väntar ändras till 1 slutar medan knappen trycks in = 0; // Återställ knapptryckning}} // -------------------- Rita en slumpmässig radinmatningsfärg uint8_t -------------- ----- void drawALineForMe (uint8_t clr) {uint8_t line1X, line1Y, line2X, line2Y = 0; // ställ in slumpmässiga koordinater för en rad och rita sedan // variabel inte mindre inte mer line1X = random (worldMinX+1, worldMaxX-1); line1Y = random (worldMinY+1, worldMaxY-1); line2X = random (worldMinX+1, worldMaxX-1); line2Y = random (worldMinY+1, worldMaxY-1); display.drawLine (line1X, line1Y, line2X, line2Y, clr); } // ------------------------------------- kollisionsdetektering -------- -----------------------

för (byte i = 4; i <snakeSize; i ++) {if (snakeX == snakePosX && snakeY == snakePosy ) {return 1; ton (SND, 2000, 20); ton (SND, 1000, 20); } returnera 0; }

//-------------------------------- UPPSTART--------------- -------------------------------

void setup () {delay (100); // bara ge saker en chans att "starta" // Serial.begin (9600); // avmarkera detta om du vill se de seriella utgångarna display.begin (SSD1306_SWITCHCAPVCC, 0x3C); display.clearDisplay (); // börja med en ren display display.setTextColor (WHITE); // ställ in textfärgrotationsstorlek etc display.setRotation (0); display.setTextWrap (falskt); display.dim (0); // ställ in skärmens ljusstyrka pinMode (INTPIN, INPUT); // ställ in rätt portar till ingångar pinMode (UPPIN, INPUT); pinMode (DWNPIN, INPUT); pinMode (LFTPIN, INPUT); pinMode (RHTPIN, INPUT); // detta är avbrottskommandot detta "stoppar" arduinoen för att läsa ingångarna // kommando- funktion- pin-funktion för att exekvera-tillstånd på pin attachInterrupt (digitalPinToInterrupt (INTPIN), interruptpressed, RISING); // Serial.println ("Setup Passed"); waitForPress (); // visa startskärmen för ormen placeScran (); // placera första bit mat} // --------------------- MAIN LOOP ----------------- ---------------------- void loop () {updateGame (); // denna funktion är det som bär huvudkoden}

Steg 3:

Rekommenderad: