Table des matières:

Arduino OLED Snake Game : 3 étapes
Arduino OLED Snake Game : 3 étapes

Vidéo: Arduino OLED Snake Game : 3 étapes

Vidéo: Arduino OLED Snake Game : 3 étapes
Vidéo: Classic Snake Game On 8x8 LED Matrix With Chat-GPT Generated Arduino Code | Coders Cafe 2024, Novembre
Anonim
Jeu de serpent Arduino OLED
Jeu de serpent Arduino OLED

Salut et bienvenue, dans nos instructables sur la façon de créer un jeu arduino OLED, ce projet a vu le jour alors que nous essayions de créer notre tout premier jeu avec un arduino, soooo, nous avons pensé par où mieux commencer que le classique de nokia Snake (enfin à au moins un clone de serpent:)).

Ce dont vous aurez besoin

Fournitures

Arduino UNO ou clone

Affichage OLED

4 diodes

Résistance 500-1k

4 boutons de manette

Buzzer piézo passif

optionnel

Planche à pain sans soudure

Veuillez noter que ces liens sont à titre d'exemple seulement

Étape 1: Le circuit

Le circuit
Le circuit

Dans l'image ci-dessus, vous pouvez voir notre circuit, nous utilisons la broche d3 sur l'arduino comme broche de demande d'interruption afin que l'arduino donne la priorité à la lecture des entrées du contrôleur qui sont d4 d5 d6 d7. Les bases du circuit sont qu'un bouton de direction est enfoncé qui passe à 5v élevé, cela active la broche de demande d'interruption (fil violet d3) et une broche de direction correspondante, la fonction d'interruption appelle une fonction de direction de mise à jour et ce code déplace le serpent en conséquence. La broche 9 est utilisée comme broche du son car il s'agit d'un PWM (~ modulation de largeur d'impulsion) qui est connecté directement à un piézo 5v sur la broche + et le - revient à 0v/masse.

(Pour info sur l'arduino uno et les clones, seuls d2 et d3 peuvent servir de broches de demande d'interruption).

Goupilles de direction:

d4 vers le haut ORANGE

d5 Bas ROSE

d6 Gauche BLEU

d7 Droite MARRON

d9 son GRIS

Chaque bouton a une entrée de connexion en 5v et une sortie qui est connectée d'abord à leur entrée numérique respective sur l'arduino, cette même sortie de chaque bouton est ensuite connectée à sa propre diode, nous utilisons les diodes pour arrêter le retour de tension vers le d'autres boutons et en les activant. À l'extrémité cathode (-) des 4 diodes, nous les joignons ensemble pour créer une jonction de sortie qui se connecte à d3, puis à travers la résistance a à 0v/terre pour tirer les broches arduino bas afin de ne pas laisser de broches flottantes lorsqu'elles ne sont pas activé.

(Pour info, une broche flottante peut recevoir une tension fantôme et provoquer un comportement inhabituel)

2 broches analogiques sont utilisées pour piloter l'affichage, ce sont les broches matérielles arduino i2c.

A5 est connecté à SCL JAUNE

A4 est connecté à SDA GREEN

La sortie +5v et 0v (terre) de l'arduino est utilisée comme source d'alimentation pour l'ensemble du circuit qui peut être alimenté par USB ou par chargeur de téléphone.

Étape 2: le code

//------------------------- ANJAWARE SNAKE Games Avec l'aide des peuples du net --------------- -------

#comprendre

#include // https://github.com/adafruit/Adafruit-GFX-Library #include // https://github.com/adafruit/Adafruit-GFX-Library // ensemble d'affichage (largeur, hauteur) Adafruit_SSD1306 display(128, 64); // définir les broches d'entrée ce sont les broches de l'arduino elles ne changent jamais donc #define #define INTPIN 3 // seules les broches 2 et 3 peuvent être des broches d'interruption sur UNO #define UPPIN 4 // ce sont des broches connectées au commutateur pertinent #define DWNPIN 5 #define LFTPIN 6 #define RHTPIN 7 #define SND 9 // définit les directions #define DIRUP 1 // ces valeurs sont ce que le "serpent" regarde pour décider- #define DIRDOWN 2 // la direction dans laquelle le serpent se déplacera # définir DIRLEFT 3 #définir DIRRIGHT 4

// définir les variables du bouton

// volitile car nous avons besoin qu'il soit mis à jour avec l'interruption, il peut donc s'agir de n'importe quel bit de valeur de cycle

// n'est jamais supérieur à 4 donc n'a besoin que de 8 bits int pour économiser les ressources volatile uint8_t buttonpressed=0; bool butup=0; bool butdown=0; // nous l'utilisons pour définir true pour "détecter" la direction enfoncée bool butleft=0; bool butright=0;

// ints de serpent

octet snakePosX[30]; // tableau pour créer le corps de l'octet serpent snakePosY[30];

int serpentX=30; // position de la tête de serpent

int serpentY=30; int SnakeSize=1; // nombre de tailles de serpent limité à la taille du tableau

// monde entier

uint8_t worldMinX=0; // ceux-ci définissent les limites de l'aire de jeu

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

// collecte le scran (nourriture) et la position du scran

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

// note les variables

score de jeu long=0; long meilleur score = 30; // définir le score élevé sur 3 collecter comme point de départ

//--------------------------- c'est ce que l'interruption exécute sur la montée en tension ------------ -------------

void interruptpressed() { delay(150); // léger délai pour l'ajout de la protection "rebond" updatedirection(); } // ------------------ mettre à jour la valeur de direction en appuyant sur le bouton ----------------- void updatedirection() { // Serial.println("updatingdirection"); butup=digitalRead(UPPIN); // vérifie quelle entrée est élevée et définit le bool pertinent true butdown=digitalRead(DWNPIN); butleft=digitalRead(LFTPIN); butright=digitalRead(RHTPIN); // ces instructions if regardent quelle entrée est élevée et entrent la valeur appropriée dans la variable "buttonpressed" // cette variable dicte la direction du mouvement if(butup==true) { buttonpressed=DIRUP; // Serial.println("UP enfoncé"); // Serial.println (bouton pressé); butup=false; tonalité (SND, 1500, 10); } if(butdown==true) { buttonpressed=DIRDOWN; // Serial.println("DOWN appuyé"); // Serial.println (bouton pressé); butdown=false; tonalité (SND, 1500, 10); }

if(butleft==true)

{ bouton enfoncé = DIRECTION GAUCHE; // Serial.println("GAUCHE enfoncé"); // Serial.println (bouton pressé); butleft=false; tonalité (SND, 1500, 10); } if(butright==true) { buttonpressed=DIRRIGHT; // Serial.println("DROITE enfoncé"); // Serial.println (bouton pressé); butright=false; tonalité (SND, 1500, 10); } }

//-------------------------- dessine les routines d'affichage------------------ -----------------

void updateDisplay() // dessine les partitions et les contours

{ // Serial.println("Mettre à jour l'affichage");

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

display.setTextSize(0); display.setTextColor(BLANC); // dessine les scores display.setCursor(2, 1); display.print("Score:"); display.print(String(playscore, DEC)); display.setCursor(66, 1); display.print("Élevé:"); display.print(String(meilleur score, DEC)); // dessiner la zone de jeu // pos 1x, 1y, 2x, 2y, color display.drawLine(0, 0, 127, 0, WHITE); // bordure supérieure display.drawLine(63, 0, 63, 9, WHITE); // séparateur de scores display.drawLine(0, 9, 127, 9, WHITE); // sous la bordure de texte display.drawLine(0, 63, 127, 63, WHITE); // bordure inférieure display.drawLine(0, 0, 0, 63, WHITE); // bordure gauche display.drawLine(127, 0, 127, 63, WHITE); // bordure droite

}

//----------------------------------- mise à jour de la zone de jeu ---------- --------------------

void updateGame() // ceci met à jour l'affichage de la zone de jeu

{ display.clearDisplay();

display.drawPixel(scranPosX, scranPosY, BLANC);

scranAte = scranNourriture();

// vérifier les routines de serpent

if (outOfArea()||selfCollision())

{ jeu terminé(); }

// affiche le serpent

for(int i=0;i0;i--) { SnakePosX = SnakePosX[i-1]; serpentPosY = serpentPosY[i-1]; } // ajoute un pixel supplémentaire au serpent if(scranAte) { snakeSize+=1; SnakePosX[snakeSize-1]=snakeX; SnakePosY[snakeSize-1]=serpentY; }

switch (bouton pressé) // était snakeDirection

{ cas DIRUP: snakeY-=1; Pause; cas DIRDOWN: serpentY+=1; Pause; cas VERS LA GAUCHE: serpentX-=1; Pause; cas DIRRIGHT: serpentX+=1; Pause; } serpentPosX[0] = serpentX; serpentPosY[0] = serpentY; mise à jourAffichage(); display.display(); // --------------------- place le scran -------------------

void placeScran()

{ scranPosX=random(worldMinX+1, worldMaxX-1); scranPosY=random(worldMinY+1, worldMaxY-1); } //------------------------ POINT DE SCRAN AT UP ---------------- bool scranFood() { if(snakeX==scranPosX&&snakeY==scranPosY) { playscore=playscore+10; tonalité (SND, 2000, 10); mise à jourAffichage(); placeScran(); retour 1; } else { return 0; } } //--------------------- hors de la zone---------------------- bool outOfArea() { return snakeX =worldMaxX ||snakeY=worldMaxY; } //---------------------- jeu terminé----------------------- --- 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); tonalité (SND, 2000, 50); display.print("JEU "); tonalité (SND, 1000, 50); display.print("OVER"); if(playscore>=highscore) //vérifier si le score est supérieur au score élevé { highscore=playscore; //instruction if unique pour mettre à jour le score élevé } for(int i=0;i<=16;i++) // ceci consiste à dessiner des rectanlges autour de la partie { display.drawRect(rectX1, rectY1, rectX2, rectY2, WHITE); Serial.println("si boucle"); display.display(); rectX1-=2; // décalage de 2 pixels rectY1-=2; rectX2+=4; // décalage de plus de 2 pixels à partir du dernier point rectY2+=4; tonalité (SND, i*200, 3); } display.display(); //Effacer l'écran après la célébrité sur rectX1=0; // définit la position de départ de la ligne rectY1=0; rectX2=0; rectY2=63; for (int i =0;i<=127;i++) { uint8_t cnt=0; display.drawLine(rectX1, rectY1, rectX2, rectY2, NOIR); rectX1++; rectX2++; display.display(); } display.clearDisplay(); score de lecture=0; // réinitialiser les détails du serpent et du joueur snakeSize=1; snakeX=display.width()/2; serpentY=affichage.hauteur ()/2; waitForPress(); // attend que le joueur commence le jeu } //------------------------ attend la boucle de presse ---------- --------------- void waitForPress() { bool wait=0; // la boucle se termine quand c'est vrai display.clearDisplay(); while(en attente==0) { drawALineForMe(WHITE); // dessine une ligne blanche aléatoire drawALineForMe(BLACK); // dessine une ligne noire aléatoire pour que l'écran ne remplisse pas complètement le blanc display.fillRect(19, 20, 90, 32, BLACK); // arrière-plan vide pour le texte display.setTextColor(WHITE); display.setCursor(35, 25); display.setTextSize(2); // police plus 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); // cadre de bordure - 3 display.setCursor(28, 42); display.setTextSize(0); // la police revient à la normale display.println("appuyez sur n'importe quelle touche"); display.display(); en attente = digitalRead(INTPIN); // vérifie si l'attente de la touche enfoncée passe à 1 et se termine lorsque buttonpressed=0; // bouton de réinitialisation appuyez sur } } //----------------------------------- DESSINEZ une couleur d'entrée de ligne aléatoire uint8_t -------------- ----- void drawAlineForMe(uint8_t clr) { uint8_t line1X, line1Y, line2X, line2Y=0; // définir des coordonnées aléatoires pour une ligne puis la dessiner // variable pas moins pas plus 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); } //------------------------------------- détection de collision -------- -----------------------

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

//-------------------------------- METTRE EN PLACE--------------- -------------------------------

void setup() { delay(100); // juste donner aux choses une chance de "démarrer" // Serial.begin(9600); // décochez cette case si vous voulez voir les sorties série display.begin(SSD1306_SWITCHCAPVCC, 0x3C); display.clearDisplay(); // commencer avec un affichage propre display.setTextColor(WHITE); // configurer la taille de rotation de la couleur du texte, etc. display.setRotation(0); display.setTextWrap(false); display.dim(0); // définit la luminosité de l'affichage pinMode(INTPIN, INPUT); // définit les ports corrects sur les entrées pinMode(UPPIN, INPUT); pinMode(DWNPIN, INPUT); pinMode(LFTPIN, INPUT); pinMode(RHTPIN, INPUT); // il s'agit de la commande d'interruption qui "arrête" l'arduino pour lire les entrées // commande-fonction-pin-fonction à exécuter-condition sur la broche attachInterrupt(digitalPinToInterrupt(INTPIN), interruptpressed, RISING); // Serial.println("Configuration réussie"); waitForPress(); // affiche l'écran de démarrage du serpent placeScran(); // place le premier morceau de nourriture } //--------------------- BOUCLE PRINCIPALE----------------- ---------------------- boucle vide() { updateGame(); // cette fonction est ce qui porte le code principal }

Étape 3:

Conseillé: