Sommario:

Gioco del serpente OLED Arduino: 3 passaggi
Gioco del serpente OLED Arduino: 3 passaggi

Video: Gioco del serpente OLED Arduino: 3 passaggi

Video: Gioco del serpente OLED Arduino: 3 passaggi
Video: Videogioco portatile Snake con SSD1306, Joystick Shield e Arduino - 3/3 - Video 698 2024, Luglio
Anonim
Gioco del serpente OLED Arduino
Gioco del serpente OLED Arduino

Ciao e benvenuto, ai nostri istruttori su come creare e Arduino OLED Game, questo progetto è nato mentre stavamo tentando di realizzare il nostro primo gioco in assoluto con un Arduino, quindi, abbiamo pensato quale fosse migliore per iniziare rispetto al classico Nokia Snake (beh a almeno un clone di serpente:)).

Di cosa avrai bisogno

Forniture

Arduino UNO o clone

Display OLED

4 diodi

Resistenza da 500-1k

4 pulsanti del controller

Cicalino piezo passivo

opzionale

Pane senza saldatura

Si prega di notare che questi collegamenti sono solo per esempio

Passaggio 1: il circuito

Il circuito
Il circuito

Nell'immagine sopra puoi vedere il nostro circuito, usiamo il pin d3 su arduino come pin di richiesta di interrupt in modo che l'arduino dia priorità alla lettura degli ingressi del controller che sono d4 d5 d6 d7. Le basi del circuito sono che viene premuto un pulsante di direzione che va alto 5v questo attiva il pin di richiesta di interruzione (filo viola d3) e un pin di direzione corrispondente, la funzione di interruzione chiama una funzione di direzione di aggiornamento e quel codice sposta il serpente di conseguenza. Il pin 9 viene utilizzato come pin del suono in quanto è un PWM (~ modulazione di larghezza di impulso) che è collegato direttamente a un piezo 5v sul pin + e il - torna a 0v/massa.

(Cordiali saluti su arduino uno e cloni solo d2 e d3 possono fungere da pin di richiesta di interruzione).

Perni di direzione:

d4 Su ARANCIO

d5 Giù ROSA

d6 BLU sinistro

d7 MARRONE destro

d9 suono GRIGIO

Ogni pulsante ha un ingresso di connessione in 5v e un'uscita che è collegata prima al rispettivo ingresso digitale sull'arduino, questa stessa uscita di ogni pulsante è poi collegata al proprio diodo, utilizziamo i diodi per interrompere il ritorno di tensione attraverso il altri pulsanti e attivandoli. All'estremità del catodo (-) di tutti e 4 i diodi li uniamo insieme per creare una giunzione di uscita che si collega a d3 e quindi attraverso un resistore a 0v/terra per abbassare i pin di arduino in modo da non lasciare i pin flottanti quando non sono attivato.

(Cordiali saluti, un pin flottante può ricevere una tensione fantasma e causare un comportamento insolito)

2 pin analogici vengono utilizzati per pilotare il display, questi sono i pin i2c dell'hardware arduino.

A5 è collegato a SCL GIALLO

A4 è collegato a SDA GREEN

L'uscita +5v e 0v (terra) dall'arduino viene utilizzata come fonte di alimentazione per l'intero circuito che può essere alimentato tramite usb o caricatore del telefono.

Passaggio 2: il codice

//--------- Giochi ANJAWARE SNAKE Con l'aiuto dei popoli della rete --------------- -------

#includere

#include // https://github.com/adafruit/Adafruit-GFX-Library #include // https://github.com/adafruit/Adafruit-GFX-Library // display set (larghezza, altezza) Adafruit_SSD1306 display(128, 64); // definisci i pin di input questi sono i pin sull'arduino non cambiano mai quindi #define #define INTPIN 3 // solo i pin 2 e 3 possono essere pin di interruzione su UNO #define UPPIN 4 // questi sono pin collegati all'interruttore pertinente #define DWNPIN 5 #define LFTPIN 6 #define RHTPIN 7 #define SND 9 // definisce le direzioni #define DIRUP 1 // questi valori sono ciò che il "serpente" guarda per decidere- #define DIRDOWN 2 // la direzione in cui viaggerà il serpente # define DIRLEFT 3 #define DIRRIGHT 4

// imposta le variabili del pulsante

// volitile cos abbiamo bisogno che si aggiorni con l'interrupt, quindi può essere qualsiasi bit del valore del ciclo

// non è mai maggiore di 4 quindi necessita solo di 8bit int per risparmiare risorse volatile uint8_t buttonpressed=0; bool butup=0; bool butdown=0; // usiamo questo per impostare true per "rilevare" quale direzione ha premuto bool butleft=0; bool butright=0;

// interi serpente

byte snakePosX[30]; // array per creare il corpo del byte snake snakePosY[30];

int serpenteX=30; // posizione della testa di serpente

int serpenteY=30; int dimensione serpente=1; // conteggio delle dimensioni del serpente limitato alla dimensione dell'array

// mondo intero

uint8_t worldMinX=0; // questi fissano i limiti dell'area di gioco

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

// raccoglie scran(cibo) e la posizione di scran

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

// variabili di punteggio

punteggio lungo=0; punteggio lungo=30; // imposta il punteggio più alto su 3 collect come punto di partenza

//------------- questo è ciò che esegue l'interrupt all'aumento di tensione ------------ -------------

void interruptpressed() { delay(150); // leggero ritardo per l'aggiunta della protezione "rimbalzo" updatedirection(); } // ------------------ aggiorna il valore della direzione dalla pressione del pulsante ------------------ void updaterection() { // Serial.println("direzione aggiornamento"); butup=digitalRead(UPPIN); // controlla quale input è andato alto e imposta il bool pertinente true butdown=digitalRead(DWNPIN); butleft=digitalRead(LFTPIN); butright=digitalRead(RHTPIN); // queste istruzioni if controllano quale input è andato alto e inserisce il valore pertinente nella variabile "buttonpressed" //, questa variabile determina la direzione del movimento if(butup==true) { buttonpressed=DIRUP; // Serial.println("SU premuto"); // Serial.println(buttonpressed); butup=falso; tono(SND, 1500, 10); } if(butdown==true) { buttonpressed=DIRDOWN; // Serial.println("GI premuto"); // Serial.println(buttonpressed); butdown=false; tono(SND, 1500, 10); }

if(butleft==true)

{ buttonpressed=DIRLEFT; // Serial.println("SINISTRO premuto"); // Serial.println(buttonpressed); butleft=false; tono(SND, 1500, 10); } if(butright==true) { buttonpressed=DIRRIGHT; // Serial.println("premuto a DESTRA"); // Serial.println(buttonpressed); butright=false; tono(SND, 1500, 10); } }

//------------disegna le routine di visualizzazione---- -----------------

void updateDisplay() // disegna punteggi e contorni

{ // Serial.println("Aggiorna visualizzazione");

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

display.setTextSize(0); display.setTextColor(BIANCO); // disegna i punteggi display.setCursor(2, 1); display.print("Punteggio:"); display.print(String(playscore, DEC)); display.setCursor(66, 1); display.print("Alto:"); display.print(String(punteggio alto, DEC)); // disegna l'area di gioco // pos 1x, 1y, 2x, 2y, color display.drawLine(0, 0, 127, 0, WHITE); // bordo in alto display.drawLine(63, 0, 63, 9, WHITE); // separatore di punteggio display.drawLine(0, 9, 127, 9, WHITE); // sotto il bordo del testo display.drawLine(0, 63, 127, 63, WHITE); // bordo inferiore display.drawLine(0, 0, 0, 63, WHITE); // bordo sinistro display.drawLine(127, 0, 127, 63, WHITE); //bordo destro

}

//------------------------------------ aggiorna l'area di gioco ------------------------- --------------------

void updateGame() // questo aggiorna la visualizzazione dell'area di gioco

{ display.clearDisplay();

display.drawPixel(scranPosX, scranPosY, WHITE);

scranAte = scranFood();

// controlla le routine del serpente

if (outOfArea()||selfCollision())

{ game Over(); }

// mostra serpente

for(int i=0;i0;i--) { snakePosX = snakePosX[i-1]; serpentePosY = serpentePosY[i-1]; } // aggiunge un pixel in più al serpente if(scranAte) { snakeSize+=1; snakePosX[snakeSize-1]=snakeX; snakePosY[snakeSize-1]=serpenteY; }

switch (pulsante premuto) // era snakeDirection

{ case DIRUP: snakeY-=1; rottura; caso DIRDOWN: serpenteY+=1; rottura; caso DIRLEFT: snakeX-=1; rottura; case DIRRIGHT: snakeX+=1; rottura; } snakePosX[0] = snakeX; serpentePosY[0] = serpenteY; updateDisplay(); display.display(); // --------------------- posiziona lo scran -------------------

vuoto placeScran()

{ scranPosX=random(worldMinX+1, worldMaxX-1); scranPosY=random(worldMinY+1, worldMaxY-1); } //--------- SCRAN ATE POINT UP ---------------- bool scranFood() { if(snakeX==scranPosX&&snakeY==scranPosY) { playcore=playscore+10; tono(SND, 2000, 10); updateDisplay(); placeScran(); ritorno 1; } else { restituisce 0; } } //--------------------- fuori zona---------------------- bool outOfArea() { return snakeX =worldMaxX ||snakeY=worldMaxY; } //---------------------- game Over----------------------- --- void gameOver() { uint8_t rectX1, rectY1, rectX2, rectY2; rectX1=38; rectY1=28; rectX2=58; rectY2=12; display.clearDisplay(); display.setCursor(40, 30); display.setTextSize(1); tono (SND, 2000, 50); display.print("GIOCO"); tono(SND, 1000, 50); display.print("SOPRA"); if(playscore>=highscore) //controlla se il punteggio è più alto del punteggio più alto { highscore=playscore; // istruzione single if per aggiornare il punteggio più alto } for(int i=0;i<=16;i++) // questo serve per disegnare i rettangoli intorno al game over { display.drawRect(rectX1, rectY1, rectX2, rectY2, WHITE); Serial.println("se ciclo"); display.display(); rectX1-=2; // sposta di 2 pixel rectY1-=2; rectX2+=4; // sposta di 2 pixel dall'ultimo punto rectY2+=4; tono(SND, i*200, 3); } display.display(); //Cancella schermo dopo la fama su rectX1=0; // imposta la posizione iniziale della riga rectY1=0; rectX2=0; rectY2=63; for (int i =0;i<=127;i++) { uint8_t cnt=0; display.drawLine(rectX1, rectY1, rectX2, rectY2, BLACK); rectX1++; rectX2++; display.display(); } display.clearDisplay(); punteggio di riproduzione=0; // resetta i dettagli del serpente e del giocatore snakeSize=1; snakeX=display.width()/2; serpenteY=display.altezza()/2; waitForPress(); // aspetta che il giocatore inizi il gioco } //-----------attendere il ciclo delle pressioni ---------- --------------- void waitForPress() { bool in attesa=0; // il ciclo termina quando questo è vero display.clearDisplay(); while(attesa==0) { drawALineForMe(WHITE); // disegna una linea bianca casuale drawALineForMe(BLACK); // traccia una linea nera casuale in modo che lo schermo non riempia completamente il bianco display.fillRect(19, 20, 90, 32, BLACK); // sfondo vuoto per il testo display.setTextColor(WHITE); display.setCursor(35, 25); display.setTextSize(2); // carattere più grande 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); // riquadro del bordo - 3 display.setCursor(28, 42); display.setTextSize(0); // font torna al normale display.println("premi un tasto qualsiasi"); display.display(); in attesa = digitalRead(INTPIN); // controlla se il tasto premuto in attesa cambierà in 1 mentre si preme il pulsante = 0; // pulsante di ripristino premere } } //------DRAW un colore di input di riga casuale uint8_t-------------- ----- void drawALineForMe(uint8_t clr) { uint8_t riga1X, riga1Y, riga2X, riga2Y=0; // imposta le coordinate casuali per una linea e poi disegnala // variabile non meno non più line1X = random(worldMinX+1, worldMaxX-1); line1Y = random(worldMinY+1, worldMaxY-1); riga2X = random(worldMinX+1, worldMaxX-1); riga2Y = random(worldMinY+1, worldMaxY-1); display.drawLine(riga1X, riga1Y, riga2X, riga2Y, clr); } //------------------------------------- rilevamento delle collisioni -------- -----------------------

for(byte i=4;i<snakeSize;i++) { if(snakeX==snakePosX&&snakeY==snakePosy) { return 1; tono(SND, 2000, 20); tono(SND, 1000, 20); } restituisce 0; }

//-------------------------------- IMPOSTARE--------------- -----------------

void setup() { delay(100); // basta dare agli oggetti la possibilità di "avviarsi" // Serial.begin(9600); // deseleziona questo se vuoi vedere le uscite seriali display.begin(SSD1306_SWITCHCAPVCC, 0x3C); display.clearDisplay(); // inizia con un display pulito display.setTextColor(WHITE); // imposta la dimensione della rotazione del colore del testo ecc. display.setRotation(0); display.setTextWrap(false); display.dim(0); // imposta la luminosità del display pinMode(INTPIN, INPUT); // imposta le porte corrette agli input pinMode(UPPIN, INPUT); pinMode(DWNPIN, INPUT); pinMode(LFTPIN, INGRESSO); pinMode(RHTPIN, INPUT); // questo è il comando di interrupt questo "ferma" l'arduino per leggere gli input //comando-funzione-pin-funzione per eseguire-condizione sul pin attachInterrupt(digitalPinToInterrupt(INTPIN), interruptpressed, RISING); // Serial.println("Installazione superata"); waitForPress(); // mostra la schermata di avvio del serpente placeScran(); // posiziona il primo pezzo di cibo } //-------MAIN LOOP--- ---------------------- void loop() { updateGame(); // questa funzione è ciò che porta il codice principale }

Passaggio 3:

Consigliato: