Project tutorial

The Flappy Bird on Arduino © GPL3+

Play the famous 'Flappy Birds' game on the Arduino Touchscreen Shield.

  • 1,139 views
  • 1 comment
  • 16 respects

Components and supplies

Ardgen mega
Arduino Mega 2560 & Genuino Mega 2560
×1
Arduino TFT Touchscreen Shied
×1

Apps and online services

About this project

Overview

This is a very simple project as far as the hardware is concerned, but with the software, we have very demanding work. On the Arduino Mega 2560 directly place the Arduino TFT LCD Touch Screen display. The program is inserted into the Arduino Mega.

The game is quite simple but interesting and addictive. Using the touch screen we control the bird and try to avoid the moving pillars which speed increase as we progress. Also the game can store your highest score even if you unplug the power.

How "Flappy Bird" works and Source Code

The "flappy" object is located in a fixed position on the X-axis while actions are performed by moving the Y-axis.

When you touch the keys or the display object, Flappy moves to -10 px Y-axis. Obstacles appear. Flappy either gets in contact with an obstacle or exits from the world which is dictated by the edges of the screen display. The game is stopped when Flappy stops and the message "GAME OVER" and an achieved score are displayed. Game stores your highest score even if you unplug the power using EEPROM.

We will use the UTFT and URTouch libraries made by Henning Karlsen. You can download these libraries from his website, www.RinkyDinkElectronics.com. Also we will use the EEPROM library for storing the highest score in the EEPROM. The EEPROM is a memory which can store data even when the board is turned off.

After we have included the libraries we need to create the UTFT and URTouch objects as well as define the variables needed for the game. In the setup section we need to initiate the display and the touch, read the highest score from the EEPROM and initiate the game using the initiateGame() custom function.

So with the initiateGame() custom function we will draw the initial state of the game and here’s how we will do that. First we need to clear the screen, then draw the blue background, draw the bottom section, add the text and call the drawBird() custom function to draw the bird. After this we need a while loop which will prevent the game to start until we tap the screen. So while we are at this state, if we press the upper right corner we can reset the highest score to zero and if we press anywhere else on the screen we will get out of the while loop and get into the main loop of the code which will start the game.

In the main loop section we have the xP variable which is used for drawing the pillars, as well as the yP variable. At the beginning, the xP variable has the value of 319 as the size of the screen and the yP variable has the value of 100 which is the height of the first pillar. Each iteration the value of the xP variable is decreased by the value of the movingRate variable which at the beginning has the value of 3 and as we progress the game it increases.

Here’s the working principle of game: we have 50 pixels wide pillars which move from right to left and every next pillar has a different random height. In order to make them moving, logically, after each iteration we need to clear the screen and redraw the graphic with the pillars at their new position. However, we cannot do that because of the low refresh rate of the screen, which would cause flickering of the graphics. In order to activate all of its pixels the screen needs a bit more time so therefore we will have to improvise and redraw just those things that are moving.

So let’s take a look how the drawPilars() custom function will do that. It takes the xP and yP variables and using them and the fillRect() function it will draw the pillars. So each iteration it draws the pillars at their new location with additional blue rectangles from their left and right side which clear the previous drawn pillar and in that way we actually do the improvisation of just redrawing the moving pillars. The if statements here are an additional improvisation because for some reason the fillRect() function didn’t work if its ‘x2’ parameter had a value out of the screen size. Also, at the end of this custom function we need to print the value of reached score.

Back in the loop section we have the yB variable which is the y position of the bird and it depends on the falling rate which after each iteration is increased and in that way we get the effect of acceleration or gravity. Also, here we check for collisions and use the if statements to confine the bird so that if it hit the top, the ground or the pillars the game will over.

Next is the drawBird() custom function and let’s see how it works. The bird is actually a photo which is converted into a bitmap using the ImageConverter565 tool made by Henning Karlsen. The “.c” file which is created using the tool needs to be included in the directory so that it load when launching the sketch. Also we have to define the bitmap like this and using the drawBitmap() function we will draw the photo on the screen. The bird has a fixed X – coordinate and the yB variable as Y – coordinate. Similar to the pillars we will clear the previous state of the bird by drawing two blue rectangles above and under the bird.

Back in the loop we can see that after the pillar has passed through the screen the xP variable will be reset to 319, yP will get new random value from 20 to 100 for the height of the pillars and the score will increase by one. With the next if statement we control the bird. If we tap the screen we will set the falling rate to negative what will make the bird jump and the else if statement will not allow to happen that if we just hold the screen. The last if statement is for the difficulty of the game and it increase the moving rate of the pillars after each fine points.

Ok what’s left now is to see how the gameOver() custom function works. After a delay of one second it will clear the screen, print the score and some text, if score is higher than the highest score it will write it down into the EEPROM, it will reset all variables to their starting position values and at the end it will call the initiateGame() custom function to restart the game.

Code

flappy_birds.inoC/C++
#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();
}

Comments

Similar projects you might like

Hacking My Toaster

Project tutorial by javier muñoz sáez

  • 182 views
  • 5 comments
  • 5 respects

Music Reactive LED Strip

Project showcase by buzzandy

  • 142 views
  • 2 comments
  • 9 respects

Pavlov's Cat

Project tutorial by Arduino

  • 307 views
  • 0 comments
  • 1 respect

Infrared Controlled Logic Puzzle -- Lights On!

Project tutorial by FIELDING

  • 105 views
  • 0 comments
  • 5 respects

Arduino Obstacle Avoidance Robot with Ultrasonic HC-SR04

Project tutorial by Jorge Rancé

  • 864 views
  • 1 comment
  • 12 respects

Using Finite State Machines

by Gustavo Gonnet

  • 7,131 views
  • 2 comments
  • 19 respects
Add projectSign up / Login