Fabrication industrielle
Internet des objets industriel | Matériaux industriels | Entretien et réparation d'équipement | Programmation industrielle |
home  MfgRobots >> Fabrication industrielle >  >> Manufacturing Technology >> Processus de fabrication

Projet de jeu Arduino - Réplique de Flappy Bird pour Arduino

Dans ce projet Arduino, nous allons créer un jeu Arduino sympa, en fait une réplique du célèbre jeu Flappy Bird pour smartphones, en utilisant un Arduino et un écran tactile TFT. Vous pouvez découvrir son fonctionnement en regardant la vidéo suivante ou en lisant le texte ci-dessous.

Aperçu

Le jeu est assez simple mais intéressant et addictif. À l'aide de l'écran tactile, nous contrôlons l'oiseau et essayons d'éviter les piliers en mouvement dont la vitesse augmente au fur et à mesure que nous progressons. De plus, le jeu peut stocker votre score le plus élevé même si vous débranchez l'alimentation.[/column]

Dans le didacticiel précédent (Tutoriel Arduino TFT), nous avons appris en détail comment utiliser les écrans tactiles TFT avec un Arduino et nous avons laissé l'exemple de jeu à expliquer dans ce didacticiel. Alors maintenant, tout comme dans le tutoriel précédent, nous allons expliquer étape par étape le code derrière ce jeu Arduino.

Code source

Comme le code est un peu plus long et pour une meilleure compréhension, je publierai le code source du programme dans des sections avec une description pour chaque section. Et à la fin de cet article, je publierai le code source complet.

Nous utiliserons les bibliothèques UTFT et URTouch créées par Henning Karlsen. Vous pouvez télécharger ces bibliothèques à partir de son site Web, www.RinkyDinkElectronics.com. Nous utiliserons également la bibliothèque EEPROM pour stocker le score le plus élevé dans l'EEPROM. L'EEPROM est une mémoire qui peut stocker des données même lorsque la carte est éteinte.

Après avoir inclus les bibliothèques, nous devons créer les objets UTFT et URTouch ainsi que définir les variables nécessaires au jeu. Dans la section de configuration, nous devons lancer l'affichage et le toucher, lire le score le plus élevé de l'EEPROM et lancer le jeu à l'aide de la fonction personnalisée initiateGame().

 #include <UTFT.h> 
#include <URTouch.h>
#include <EEPROM.h>

//==== Creating Objects
UTFT    myGLCD(SSD1289,38,39,40,41); //Parameters should be adjusted to your Display/Schield model
URTouch  myTouch( 6, 5, 4, 3, 2);

//==== Defining Fonts
extern uint8_t SmallFont[];
extern uint8_t BigFont[];
extern uint8_t SevenSegNumFont[];

extern unsigned int bird01[0x41A]; // Bird Bitmap

int x, y; // Variables for the coordinates where the display has been pressed

// Floppy Bird
int xP = 319;
int yP = 100;
int yB = 50;
int movingRate = 3;
int fallRateInt = 0;
float fallRate = 0;
int score = 0;
int lastSpeedUpScore = 0;
int highestScore;
boolean screenPressed = false;
boolean gameStarted = false;

void setup() {
  // Initiate display
  myGLCD.InitLCD();
  myGLCD.clrScr();
  myTouch.InitTouch();
  myTouch.setPrecision(PREC_MEDIUM);
  
  highestScore = EEPROM.read(0); // Read the highest score from the EEPROM
  
  initiateGame(); // Initiate the game
}Code language: Arduino (arduino)

Ainsi, avec la fonction personnalisée initiateGame(), nous allons dessiner l'état initial du jeu et voici comment nous allons procéder. Nous devons d'abord effacer l'écran, puis dessiner le fond bleu, dessiner la section inférieure, ajouter le texte et appeler la fonction personnalisée drawBird() pour dessiner l'oiseau. Après cela, nous avons besoin d'une boucle while qui empêchera le jeu de démarrer jusqu'à ce que nous tapions sur l'écran. Ainsi, pendant que nous sommes dans cet état, si nous appuyons sur le coin supérieur droit, nous pouvons réinitialiser le score le plus élevé à zéro et si nous appuyons n'importe où ailleurs sur l'écran, nous sortirons de la boucle while et entrerons dans la boucle principale du code qui commencera le jeu.

// ===== initiateGame - Custom Function
void initiateGame() {
  myGLCD.clrScr();
  // Blue background
  myGLCD.setColor(114, 198, 206);
  myGLCD.fillRect(0,0,319,239);
  // Ground
  myGLCD.setColor(221,216,148);
  myGLCD.fillRect(0, 215, 319, 239);
  myGLCD.setColor(47,175,68);
  myGLCD.fillRect(0, 205, 319, 214);
  // Text
  myGLCD.setColor(0, 0, 0);
  myGLCD.setBackColor(221, 216, 148);
  myGLCD.setFont(BigFont);
  myGLCD.print("Score:",5,220);
  myGLCD.setFont(SmallFont);
  myGLCD.print("HowToMechatronics.com", 140, 220); 
  myGLCD.setColor(0, 0, 0);
  myGLCD.setBackColor(114, 198, 206);
  myGLCD.print("Highest Score: ",5,5);
  myGLCD.printNumI(highestScore, 120, 6);
  myGLCD.print(">RESET<",255,5);
  myGLCD.drawLine(0,23,319,23);
  myGLCD.print("TAP TO START",CENTER,100);
  
  drawBird(yB); // Draws the bird
  
  // Wait until we tap the sreen
  while (!gameStarted) {
    if (myTouch.dataAvailable()) {
    myTouch.read();
    x=myTouch.getX();
    y=myTouch.getY();        
    // Reset higest score
    if ((x>=250) && (x<=319) &&(y>=0) && (y<=28)) {
    highestScore = 0;
    myGLCD.setColor(114, 198, 206);
    myGLCD.fillRect(120, 0, 150, 22);
    myGLCD.setColor(0, 0, 0);
    myGLCD.printNumI(highestScore, 120, 5);
    } 
    if ((x>=0) && (x<=319) &&(y>=30) && (y<=239)) {
    gameStarted = true;
    myGLCD.setColor(114, 198, 206);
    myGLCD.fillRect(0, 0, 319, 32);
    }   
  }
  }
  // Clears the text "TAP TO START" before the game start
  myGLCD.setColor(114, 198, 206);
  myGLCD.fillRect(85, 100, 235, 116);
  
}Code language: Arduino (arduino)

Dans la section principale de la boucle, nous avons la variable xP qui est utilisée pour dessiner les piliers, ainsi que la variable yP. Au départ, la variable xP a la valeur de 319 comme taille de l'écran et la variable yP a la valeur de 100 qui est la hauteur du premier pilier. À chaque itération, la valeur de la variable xP est diminuée de la valeur de la variable movingRate qui au début a la valeur de 3 et au fur et à mesure que nous progressons dans le jeu, elle augmente.

// The Main Loop Section
void loop() {
    xP=xP-movingRate; // xP - x coordinate of the pilars; range: 319 - (-51)   
    drawPilars(xP, yP); // Draws the pillars 
    
    // yB - y coordinate of the bird which depends on value of the fallingRate variable
    yB+=fallRateInt; 
    fallRate=fallRate+0.4; // Each inetration the fall rate increase so that we can the effect of acceleration/ gravity
    fallRateInt= int(fallRate);
    
    // Checks for collision
    if(yB>=180 || yB<=0){ // top and bottom
      gameOver();
    }
    if((xP<=85) && (xP>=5) && (yB<=yP-2)){ // upper pillar
      gameOver();
    }
    if((xP<=85) && (xP>=5) && (yB>=yP+60)){ // lower pillar
      gameOver();
    }
    
    // Draws the bird
    drawBird(yB);

    // After the pillar has passed through the screen
    if (xP<=-51){
      xP=319; // Resets xP to 319
      yP = rand() % 100+20; // Random number for the pillars height
      score++; // Increase score by one
    }
    //==== Controlling the bird
    if (myTouch.dataAvailable()&& !screenPressed) {
       fallRate=-6; // Setting the fallRate negative will make the bird jump
       screenPressed = true;
    }
    // Doesn't allow holding the screen / you must tap it
    else if ( !myTouch.dataAvailable() && screenPressed){
      screenPressed = false;
    }
    
    // After each five points, increases the moving rate of the pillars
    if ((score - lastSpeedUpScore) == 5) {
      lastSpeedUpScore = score;
      movingRate++;
    }
}Code language: Arduino (arduino)

Voici le principe de fonctionnement du jeu :nous avons des piliers de 50 pixels de large qui se déplacent de droite à gauche et chaque pilier suivant a une hauteur aléatoire différente. Afin de les faire bouger, logiquement, après chaque itération, nous devons effacer l'écran et redessiner le graphique avec les piliers à leur nouvelle position. Cependant, nous ne pouvons pas le faire en raison du faible taux de rafraîchissement de l'écran, ce qui provoquerait un scintillement des graphismes. Afin d'activer tous ses pixels, l'écran a besoin d'un peu plus de temps, nous devrons donc improviser et redessiner uniquement les choses qui bougent.

Voyons donc comment la fonction personnalisée drawPilars() fera cela. Il prend les variables xP et yP et les utilise avec la fonction fillRect() pour dessiner les piliers. Ainsi, à chaque itération, il dessine les piliers à leur nouvel emplacement avec des rectangles bleus supplémentaires de leur côté gauche et droit qui effacent le pilier dessiné précédent et de cette façon nous faisons en fait l'improvisation de simplement redessiner les piliers mobiles. Les instructions if ici sont une improvisation supplémentaire car, pour une raison quelconque, la fonction fillRect() ne fonctionnait pas si son paramètre 'x2' avait une valeur hors de la taille de l'écran. De plus, à la fin de cette fonction personnalisée, nous devons imprimer la valeur du score atteint.

// ===== drawPlillars - Custom Function
void drawPilars(int x, int y) {
    if (x>=270){
      myGLCD.setColor(0, 200, 20);
      myGLCD.fillRect(318, 0, x, y-1);
      myGLCD.setColor(0, 0, 0);
      myGLCD.drawRect(319, 0, x-1, y);

      myGLCD.setColor(0, 200, 20);
      myGLCD.fillRect(318, y+81, x, 203);
      myGLCD.setColor(0, 0, 0);
      myGLCD.drawRect(319, y+80, x-1, 204); 
    }
    else if( x<=268) {
      // Draws blue rectangle right of the pillar
      myGLCD.setColor(114, 198, 206);
      myGLCD.fillRect(x+51, 0, x+60, y);
      // Draws the pillar
      myGLCD.setColor(0, 200, 20);
      myGLCD.fillRect(x+49, 1, x+1, y-1);
      // Draws the black frame of the pillar
      myGLCD.setColor(0, 0, 0);
      myGLCD.drawRect(x+50, 0, x, y);
      // Draws the blue rectangle left of the pillar
      myGLCD.setColor(114, 198, 206);
      myGLCD.fillRect(x-1, 0, x-3, y);

      // The bottom pillar
      myGLCD.setColor(114, 198, 206);
      myGLCD.fillRect(x+51, y+80, x+60, 204);
      myGLCD.setColor(0, 200, 20);
      myGLCD.fillRect(x+49, y+81, x+1, 203);
      myGLCD.setColor(0, 0, 0);
      myGLCD.drawRect(x+50, y+80, x, 204);
      myGLCD.setColor(114, 198, 206);
      myGLCD.fillRect(x-1, y+80, x-3, 204);
  }
  // Draws the score
  myGLCD.setColor(0, 0, 0);
  myGLCD.setBackColor(221, 216, 148);
  myGLCD.setFont(BigFont);
  myGLCD.printNumI(score, 100, 220);
}Code language: Arduino (arduino)

De retour dans la section de la boucle, nous avons la variable yB qui est la position y de l'oiseau et cela dépend du taux de chute qui après chaque itération est augmenté et de cette façon nous obtenons l'effet de l'accélération ou de la gravité. De plus, ici, nous vérifions les collisions et utilisons les instructions if pour confiner l'oiseau afin que s'il touche le haut, le sol ou les piliers, le jeu se termine.

Vient ensuite la fonction personnalisée drawBird() et voyons comment cela fonctionne. L'oiseau est en fait une photo qui est convertie en bitmap à l'aide de l'outil ImageConverter565 créé par Henning Karlsen. Le fichier ".c" qui est créé à l'aide de l'outil doit être inclus dans le répertoire afin qu'il se charge lors du lancement de l'esquisse. Nous devons également définir le bitmap comme ceci et en utilisant la fonction drawBitmap() nous allons dessiner la photo sur l'écran. L'oiseau a une coordonnée X fixe et la variable yB comme coordonnée Y. Comme pour les piliers, nous effacerons l'état précédent de l'oiseau en dessinant deux rectangles bleus au-dessus et en dessous de l'oiseau.

//====== drawBird() - Custom Function
void drawBird(int y) {
  // Draws the bird - bitmap
  myGLCD.drawBitmap (50, y, 35, 30, bird01);
  // Draws blue rectangles above and below the bird in order to clear its previus state
  myGLCD.setColor(114, 198, 206);
  myGLCD.fillRoundRect(50,y,85,y-6);
  myGLCD.fillRoundRect(50,y+30,85,y+36);
}Code language: Arduino (arduino)

De retour dans la boucle, nous pouvons voir qu'après que le pilier a traversé l'écran, la variable xP sera réinitialisée à 319, yP obtiendra une nouvelle valeur aléatoire de 20 à 100 pour la hauteur des piliers et le score augmentera de un. Avec la prochaine instruction if, nous contrôlons l'oiseau. Si nous tapons sur l'écran, nous réglerons le taux de chute sur négatif, ce qui fera sauter l'oiseau et l'instruction else if ne permettra pas que cela se produise si nous tenons simplement l'écran. La dernière instruction if concerne la difficulté du jeu et augmente la vitesse de déplacement des piliers après chaque point fin.

Ok, il ne reste plus qu'à voir comment fonctionne la fonction personnalisée gameOver(). Après un délai d'une seconde, il effacera l'écran, imprimera le score et du texte, si le score est supérieur au score le plus élevé, il l'écrira dans l'EEPROM, il réinitialisera toutes les variables à leurs valeurs de position de départ et à la fin il appellera la fonction personnalisée initiateGame() pour redémarrer le jeu.

//======== gameOver() - Custom Function
void gameOver() {
  delay(1000); // 1 second
  // Clears the screen and prints the text
  myGLCD.clrScr();
  myGLCD.setColor(255, 255, 255);
  myGLCD.setBackColor(0, 0, 0);
  myGLCD.setFont(BigFont);
  myGLCD.print("GAME OVER", CENTER, 40);
  myGLCD.print("Score:", 100, 80);
  myGLCD.printNumI(score,200, 80);
  myGLCD.print("Restarting...", CENTER, 120);
  myGLCD.setFont(SevenSegNumFont);
  myGLCD.printNumI(2,CENTER, 150);
  delay(1000);
  myGLCD.printNumI(1,CENTER, 150);
  delay(1000);
  
  // Writes the highest score in the EEPROM
  if (score > highestScore) {
    highestScore = score;
    EEPROM.write(0,highestScore);
  }
  // Resets the variables to start position values
  xP=319;
  yB=50;
  fallRate=0;
  score = 0;
  lastSpeedUpScore = 0;
  movingRate = 3;  
  gameStarted = false;
  // Restart game
  initiateGame();
}Code language: Arduino (arduino)

C'est tout et j'espère que l'explication du code était assez claire. Si vous avez des questions, n'hésitez pas à les poser dans la section des commentaires ci-dessous.

Voici le code complet du jeu :

/*  Arduino Game Proejct
 *  Program made by Dejan Nedelkovski,
 *  www.HowToMechatronics.com 
 */
 
/*  This program uses the UTFT and URTouch libraries
 *  made by Henning Karlsen. 
 *  You can find and download them at:
 *  www.RinkyDinkElectronics.com
 */
 
#include <UTFT.h> 
#include <URTouch.h>
#include <EEPROM.h>

//==== Creating Objects
UTFT    myGLCD(SSD1289,38,39,40,41); //Parameters should be adjusted to your Display/Schield model
URTouch  myTouch( 6, 5, 4, 3, 2);

//==== Defining Fonts
extern uint8_t SmallFont[];
extern uint8_t BigFont[];
extern uint8_t SevenSegNumFont[];

extern unsigned int bird01[0x41A]; // Bird Bitmap

int x, y; // Variables for the coordinates where the display has been pressed

// Floppy Bird
int xP = 319;
int yP = 100;
int yB = 50;
int movingRate = 3;
int fallRateInt = 0;
float fallRate = 0;
int score = 0;
int lastSpeedUpScore = 0;
int highestScore;
boolean screenPressed = false;
boolean gameStarted = false;

void setup() {
  // Initiate display
  myGLCD.InitLCD();
  myGLCD.clrScr();
  myTouch.InitTouch();
  myTouch.setPrecision(PREC_MEDIUM);
  
  highestScore = EEPROM.read(0); // Read the highest score from the EEPROM
  
  initiateGame(); // Initiate the game
}

void loop() {
    xP=xP-movingRate; // xP - x coordinate of the pilars; range: 319 - (-51)   
    drawPilars(xP, yP); // Draws the pillars 
    
    // yB - y coordinate of the bird which depends on value of the fallingRate variable
    yB+=fallRateInt; 
    fallRate=fallRate+0.4; // Each inetration the fall rate increase so that we can the effect of acceleration/ gravity
    fallRateInt= int(fallRate);
    
    // Checks for collision
    if(yB>=180 || yB<=0){ // top and bottom
      gameOver();
    }
    if((xP<=85) && (xP>=5) && (yB<=yP-2)){ // upper pillar
      gameOver();
    }
    if((xP<=85) && (xP>=5) && (yB>=yP+60)){ // lower pillar
      gameOver();
    }
    
    // Draws the bird
    drawBird(yB);

    // After the pillar has passed through the screen
    if (xP<=-51){
      xP=319; // Resets xP to 319
      yP = rand() % 100+20; // Random number for the pillars height
      score++; // Increase score by one
    }
    //==== Controlling the bird
    if (myTouch.dataAvailable()&& !screenPressed) {
       fallRate=-6; // Setting the fallRate negative will make the bird jump
       screenPressed = true;
    }
    // Doesn't allow holding the screen / you must tap it
    else if ( !myTouch.dataAvailable() && screenPressed){
      screenPressed = false;
    }
    
    // After each five points, increases the moving rate of the pillars
    if ((score - lastSpeedUpScore) == 5) {
      lastSpeedUpScore = score;
      movingRate++;
    }
}
// ===== initiateGame - Custom Function
void initiateGame() {
  myGLCD.clrScr();
  // Blue background
  myGLCD.setColor(114, 198, 206);
  myGLCD.fillRect(0,0,319,239);
  // Ground
  myGLCD.setColor(221,216,148);
  myGLCD.fillRect(0, 215, 319, 239);
  myGLCD.setColor(47,175,68);
  myGLCD.fillRect(0, 205, 319, 214);
  // Text
  myGLCD.setColor(0, 0, 0);
  myGLCD.setBackColor(221, 216, 148);
  myGLCD.setFont(BigFont);
  myGLCD.print("Score:",5,220);
  myGLCD.setFont(SmallFont);
  myGLCD.print("HowToMechatronics.com", 140, 220); 
  myGLCD.setColor(0, 0, 0);
  myGLCD.setBackColor(114, 198, 206);
  myGLCD.print("Highest Score: ",5,5);
  myGLCD.printNumI(highestScore, 120, 6);
  myGLCD.print(">RESET<",255,5);
  myGLCD.drawLine(0,23,319,23);
  myGLCD.print("TAP TO START",CENTER,100);
  
  drawBird(yB); // Draws the bird
  
  // Wait until we tap the sreen
  while (!gameStarted) {
    if (myTouch.dataAvailable()) {
    myTouch.read();
    x=myTouch.getX();
    y=myTouch.getY();        
    // Reset higest score
    if ((x>=250) && (x<=319) &&(y>=0) && (y<=28)) {
    highestScore = 0;
    myGLCD.setColor(114, 198, 206);
    myGLCD.fillRect(120, 0, 150, 22);
    myGLCD.setColor(0, 0, 0);
    myGLCD.printNumI(highestScore, 120, 5);
    } 
    if ((x>=0) && (x<=319) &&(y>=30) && (y<=239)) {
    gameStarted = true;
    myGLCD.setColor(114, 198, 206);
    myGLCD.fillRect(0, 0, 319, 32);
    }   
  }
  }
  // Clears the text "TAP TO START" before the game start
  myGLCD.setColor(114, 198, 206);
  myGLCD.fillRect(85, 100, 235, 116);
  
}
// ===== drawPlillars - Custom Function
void drawPilars(int x, int y) {
    if (x>=270){
      myGLCD.setColor(0, 200, 20);
      myGLCD.fillRect(318, 0, x, y-1);
      myGLCD.setColor(0, 0, 0);
      myGLCD.drawRect(319, 0, x-1, y);

      myGLCD.setColor(0, 200, 20);
      myGLCD.fillRect(318, y+81, x, 203);
      myGLCD.setColor(0, 0, 0);
      myGLCD.drawRect(319, y+80, x-1, 204); 
    }
    else if( x<=268) {
      // Draws blue rectangle right of the pillar
      myGLCD.setColor(114, 198, 206);
      myGLCD.fillRect(x+51, 0, x+60, y);
      // Draws the pillar
      myGLCD.setColor(0, 200, 20);
      myGLCD.fillRect(x+49, 1, x+1, y-1);
      // Draws the black frame of the pillar
      myGLCD.setColor(0, 0, 0);
      myGLCD.drawRect(x+50, 0, x, y);
      // Draws the blue rectangle left of the pillar
      myGLCD.setColor(114, 198, 206);
      myGLCD.fillRect(x-1, 0, x-3, y);

      // The bottom pillar
      myGLCD.setColor(114, 198, 206);
      myGLCD.fillRect(x+51, y+80, x+60, 204);
      myGLCD.setColor(0, 200, 20);
      myGLCD.fillRect(x+49, y+81, x+1, 203);
      myGLCD.setColor(0, 0, 0);
      myGLCD.drawRect(x+50, y+80, x, 204);
      myGLCD.setColor(114, 198, 206);
      myGLCD.fillRect(x-1, y+80, x-3, 204);
  }
  // Draws the score
  myGLCD.setColor(0, 0, 0);
  myGLCD.setBackColor(221, 216, 148);
  myGLCD.setFont(BigFont);
  myGLCD.printNumI(score, 100, 220);
}

//====== drawBird() - Custom Function
void drawBird(int y) {
  // Draws the bird - bitmap
  myGLCD.drawBitmap (50, y, 35, 30, bird01);
  // Draws blue rectangles above and below the bird in order to clear its previus state
  myGLCD.setColor(114, 198, 206);
  myGLCD.fillRoundRect(50,y,85,y-6);
  myGLCD.fillRoundRect(50,y+30,85,y+36);
}
//======== gameOver() - Custom Function
void gameOver() {
  delay(3000); // 1 second
  // Clears the screen and prints the text
  myGLCD.clrScr();
  myGLCD.setColor(255, 255, 255);
  myGLCD.setBackColor(0, 0, 0);
  myGLCD.setFont(BigFont);
  myGLCD.print("GAME OVER", CENTER, 40);
  myGLCD.print("Score:", 100, 80);
  myGLCD.printNumI(score,200, 80);
  myGLCD.print("Restarting...", CENTER, 120);
  myGLCD.setFont(SevenSegNumFont);
  myGLCD.printNumI(2,CENTER, 150);
  delay(1000);
  myGLCD.printNumI(1,CENTER, 150);
  delay(1000);
  
  // Writes the highest score in the EEPROM
  if (score > highestScore) {
    highestScore = score;
    EEPROM.write(0,highestScore);
  }
  // Resets the variables to start position values
  xP=319;
  yB=50;
  fallRate=0;
  score = 0;
  lastSpeedUpScore = 0;
  movingRate = 3;  
  gameStarted = false;
  // Restart game
  initiateGame();
}Code language: Arduino (arduino)

Voici un fichier à télécharger avec le croquis Arduino, l'image de l'oiseau et le fichier bitmap de l'oiseau.


Processus de fabrication

  1. Créer un moniteur Ambilight à l'aide d'Arduino
  2. Jeu Arduino Pong - Écran OLED
  3. Contrôleur de jeu Arduino
  4. Arduino Touch Breakout Game
  5. Giant Animatronics Lego Minfig Operation Game
  6. Détecteur de fréquence audio
  7. Tech-TicTacToe
  8. compte à rebours Arduino
  9. Jeu Pixel Chaser