CodeHub
HomeUploadContact
Back to Hub

Arduino flappy bird game

April 11, 2026 Watch Tutorial

Wiring Schematic

Arduino flappy bird game wiring diagram

Hardware Required

  • Arduino board
    Buy on Amazon

Source Code

Arduino / C++
1#include <Adafruit_GFX.h>    // Core graphics library
2#include <MCUFRIEND_kbv.h>
3#include "TouchScreen.h"
4#include <Fonts/Org_01.h>    //Include a different font
5#include <EEPROM.h> 
6MCUFRIEND_kbv tft;  
7
8/*______Define LCD pins_______*/
9#define YP A1  
10#define XM A2  
11#define YM 7   
12#define XP 6   
13#define LCD_CS A3
14#define LCD_CD A2
15#define LCD_WR A1
16#define LCD_RD A0
17#define LCD_RESET A4
18
19#define REDBAR_MINX 50
20#define GREENBAR_MINX 130
21#define BLUEBAR_MINX 180
22#define BAR_MINY 30
23#define BAR_HEIGHT 250
24#define BAR_WIDTH 30
25
26/*______Color Definitions_______*/
27#define BLACK   0x0000
28#define BLUE    0x001F
29#define RED     0xF800
30#define GREEN   0x07E0
31#define CYAN    0x07FF
32#define MAGENTA 0xF81F
33#define YELLOW  0xFFE0
34#define WHITE   0xFFFF
35#define GREY    0x8410 
36#define LIME    0x07E0
37
38// --- THE PERFECT FLAPPY BIRD SKY COLOR ---
39#define SKYBLUE 0x4F19
40
41  
42
43int currentpcolour;
44bool backsensed = false;
45bool resetsensed = false;
46#define MINPRESSURE 10
47#define MAXPRESSURE 1000
48
49/*____Calibrate TFT LCD_____*/
50#define TS_MINX 910  
51#define TS_MINY 760  
52#define TS_MAXX 180  
53#define TS_MAXY 135  
54
55TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300); 
56
57#define DRAW_LOOP_INTERVAL 50 
58#define addr 0
59
60int currentpage;
61int currentWing;        
62int flX, flY, fallRate; 
63int pillarPos, gapPosition;  
64int score;              
65int highScore = 0;      
66bool running = false;   
67bool crashed = false;   
68bool scrPress = false;  
69long nextDrawLoopRunTime;
70
71int redval, greenval, blueval;
72int redpos = BAR_MINY + 12;
73int greenpos = BAR_MINY + 12;
74int bluepos = BAR_MINY + 12;
75
76// --- Helper to fix black screen issue ---
77TSPoint safeGetPoint() {
78  TSPoint p = ts.getPoint();
79  pinMode(XM, OUTPUT);
80  pinMode(YP, OUTPUT);
81  pinMode(XP, OUTPUT); 
82  pinMode(YM, OUTPUT); 
83  return p;
84}
85
86// Forward Declarations
87void drawHome();
88void startGame();
89void drawLoop();
90void checkCollision();
91void clearPillar(int x, int gap);
92void clearFlappy(int x, int y);
93void drawPillar(int x, int gap);
94void drawFlappy(int x, int y);
95void drawWing1(int x, int y);
96void drawWing2(int x, int y);
97void drawWing3(int x, int y);
98void ResetScore();
99void sensereset();
100void senseBack();
101void drawrgb();
102void drawOSC();
103void awesomeIntro(); 
104
105void setup() {
106  Serial.begin(9600); 
107  tft.reset(); 
108  uint16_t identifier = tft.readID();
109  if (identifier == 0xEFEF) identifier = 0x9486;
110  tft.begin(identifier); 
111  
112  tft.setRotation(1); 
113  tft.invertDisplay(0);
114
115  currentpage = 0;
116  
117  // Awesome Intro
118  awesomeIntro();
119  
120  drawHome();
121}
122
123void awesomeIntro() {
124  tft.fillScreen(BLACK);
125  
126  tft.setTextColor(LIME);
127  tft.setTextSize(2);
128  tft.setCursor(10, 10);
129  tft.print("SYSTEM BOOTING...");
130  delay(300);
131
132  tft.setTextSize(1);
133  tft.setCursor(10, 40); tft.print("> Loading Kernel..."); delay(150);
134  tft.setCursor(10, 55); tft.print("> Verifying Display..."); delay(150);
135  tft.setCursor(10, 70); tft.print("> Calibrating Touch..."); delay(150);
136  tft.setCursor(10, 85); tft.print("> Tech Vibes Module..."); delay(150);
137  tft.setCursor(10, 100); tft.print("> Loading Flappy Assets..."); delay(150);
138
139  tft.drawRect(10, 150, 300, 20, WHITE);
140  for(int i=0; i<296; i+=5) { 
141    tft.fillRect(12, 152, i, 16, LIME);
142    delay(random(5, 20)); 
143  }
144  
145  delay(200);
146  tft.fillScreen(BLACK);
147  tft.setCursor(40, 100);
148  tft.setTextSize(3);
149  tft.setTextColor(GREEN);
150  tft.print("ACCESS GRANTED");
151  delay(1000);
152}
153
154void drawHome()
155{
156  tft.fillScreen(BLACK);
157  tft.drawRoundRect(0, 0, 319, 240, 8, WHITE);     
158
159  tft.fillRoundRect(60, 180, 200, 40, 8, RED);
160  tft.drawRoundRect(60, 180, 200, 40, 8, WHITE);  
161
162  tft.setTextSize(3);
163  tft.setFont();
164  
165  // 3D Shadow Effect
166  tft.setCursor(73, 103);
167  tft.setTextColor(GREY);
168  tft.print("FLAPPY GAME");
169  
170  tft.setCursor(70, 100);
171  tft.setTextColor(WHITE);
172  tft.print("FLAPPY GAME");
173  
174  tft.setCursor(50, 30);
175  tft.setTextSize(2);
176  tft.setTextColor(LIME);
177  tft.print("Tech Vibes");
178  tft.setTextColor(WHITE);
179  tft.setTextSize(3);
180  tft.setCursor(115, 190);
181  tft.print("START");
182}
183
184void loop() {
185  TSPoint p = safeGetPoint();
186
187  if (currentpage == 0)
188  {
189    if (p.z > MINPRESSURE && p.z < MAXPRESSURE)
190    {
191      if (p.x > 300 && p.x < 750 && p.y > 660 && p.y < 750)
192      {
193        tft.fillRoundRect(60, 180, 200, 40, 8, WHITE);
194        delay(70);
195        tft.fillRoundRect(60, 180, 200, 40, 8, RED);
196        tft.drawRoundRect(60, 180, 200, 40, 8, WHITE);
197        tft.setCursor(115, 190);
198        tft.setTextSize(3);
199        tft.print("START");
200
201        currentpage = 1;
202        nextDrawLoopRunTime = millis() + DRAW_LOOP_INTERVAL;
203        crashed = false;
204        running = false;
205        scrPress = false;
206        startGame();
207      }
208      else if (p.x > 563 && p.x < 683 && p.y > 275 && p.y < 750)
209      {
210        currentpage = 2;
211        drawrgb();
212      }
213      else if (p.x > 403 && p.x < 525 && p.y > 271 && p.y < 725)
214      {
215        currentpage = 3;
216        drawOSC();
217      }
218    }
219  }
220
221  if (currentpage == 1) //Flappy bird
222  {
223    senseBack();
224    if (millis() > nextDrawLoopRunTime && !crashed) {
225      drawLoop();
226      checkCollision();
227      nextDrawLoopRunTime += DRAW_LOOP_INTERVAL;
228    }
229    if (backsensed)
230    {
231      currentpage = 0;
232      drawHome();
233      delay(200); 
234      return;
235    }
236
237    sensereset();
238    ResetScore();
239
240    if (p.z > MINPRESSURE && p.z < MAXPRESSURE) {
241      if (p.y > 300 && p.x < 600 && !scrPress && !resetsensed && !backsensed) { 
242        if (crashed) {
243          startGame();
244        }
245        else if (!running) {
246          tft.fillRect(0, 0, 320, 80, SKYBLUE); 
247          running = true;
248        }
249        else
250        {
251          fallRate = -8;
252          scrPress = true;
253        }
254      }
255    }
256    else {
257      scrPress = false;
258    }
259  }
260  
261  if (currentpage == 2 || currentpage == 3) {
262      if (p.z > MINPRESSURE && p.z < MAXPRESSURE) {
263          if(p.x > 700) { 
264             currentpage = 0;
265             drawHome();
266             delay(200);
267          }
268      }
269  }
270}
271
272void drawLoop() { 
273  clearPillar(pillarPos, gapPosition);   
274  clearFlappy(flX, flY);            
275
276  if (running) {
277    flY += fallRate;
278    fallRate++;
279
280    pillarPos -= 5;
281    if (pillarPos == 0) {
282      score++; // Score +1
283    }
284    else if (pillarPos < -50) {
285      pillarPos = 320;
286      gapPosition = random(20, 120);    
287    }
288  }
289
290  drawPillar(pillarPos, gapPosition);   
291  drawFlappy(flX, flY);            
292  switch (currentWing) {     
293    case 0: case 1: drawWing1(flX, flY); break;  
294    case 2: case 3: drawWing2(flX, flY); break;  
295    case 4: case 5: drawWing3(flX, flY); break;  
296  }
297  if (score == EEPROM.read(0) ) 
298    currentpcolour = YELLOW;
299  else
300    currentpcolour = GREEN;
301
302  currentWing++;   
303  if (currentWing == 6  ) currentWing = 0;  
304}
305
306void checkCollision() {
307  if (flY > 206) crashed = true;
308
309  if (flX + 34 > pillarPos && flX < pillarPos + 50)
310    if (flY < gapPosition || flY + 24 > gapPosition + 90)
311      crashed = true;
312
313  if (score >= 999) { // WINNING CONDITION
314      tft.fillScreen(YELLOW);
315      tft.setTextColor(RED);
316      tft.setTextSize(4);
317      tft.setCursor(40, 100);
318      tft.print("YOU WIN!");
319      delay(3000);
320      currentpage=0;
321      drawHome();
322      return;
323  }
324
325  if (crashed) {      
326    tft.setTextColor(RED);   
327    tft.setTextSize(5);      
328    tft.setCursor(20, 75);   
329    tft.print("Game Over!"); 
330
331    tft.setTextSize(4);      
332    tft.setCursor(75, 125);  
333    tft.print("Score:");     
334
335    tft.setCursor(220, 125); 
336    tft.setTextSize(5);      
337    tft.setTextColor(WHITE);
338    
339    tft.print(score);        
340
341    if (score > highScore) {           
342      highScore = score;
343      EEPROM.write(addr, highScore);  
344      tft.setCursor(75, 175);          
345      tft.setTextSize(4);              
346      tft.setTextColor(YELLOW);
347      tft.print("NEW HIGH!");          
348    }
349    running = false;      
350    delay(1000);
351  }
352}
353
354void drawPillar(int x, int gap) {  
355  tft.fillRect(x + 2, 2, 46, gap - 4, currentpcolour);
356  tft.fillRect(x + 2, gap + 92, 46, 136 - gap, currentpcolour);
357  tft.drawRect(x, 0, 50, gap, BLACK);
358  tft.drawRect(x + 1, 1, 48, gap - 2, BLACK);
359  tft.drawRect(x, gap + 90, 50, 140 - gap, BLACK);
360  tft.drawRect(x + 1, gap + 91 , 48, 138 - gap, BLACK);
361}
362
363void clearPillar(int x, int gap) {  
364  tft.fillRect(x + 45, 0, 5, gap, SKYBLUE);
365  tft.fillRect(x + 45, gap + 90, 5, 140 - gap, SKYBLUE);
366}
367
368void clearFlappy(int x, int y) {  
369  tft.fillRect(x, y, 34, 24, SKYBLUE);
370}
371
372void drawFlappy(int x, int y) {  
373  tft.fillRect(x + 2, y + 8, 2, 10, BLACK);
374  tft.fillRect(x + 4, y + 6, 2, 2, BLACK);
375  tft.fillRect(x + 6, y + 4, 2, 2, BLACK);
376  tft.fillRect(x + 8, y + 2, 4, 2, BLACK);
377  tft.fillRect(x + 12, y, 12, 2, BLACK);
378  tft.fillRect(x + 24, y + 2, 2, 2, BLACK);
379  tft.fillRect(x + 26, y + 4, 2, 2, BLACK);
380  tft.fillRect(x + 28, y + 6, 2, 6, BLACK);
381  tft.fillRect(x + 10, y + 22, 10, 2, BLACK);
382  tft.fillRect(x + 4, y + 18, 2, 2, BLACK);
383  tft.fillRect(x + 6, y + 20, 4, 2, BLACK);
384  tft.fillRect(x + 12, y + 2, 6, 2, YELLOW);
385  tft.fillRect(x + 8, y + 4, 8, 2, YELLOW);
386  tft.fillRect(x + 6, y + 6, 10, 2, YELLOW);
387  tft.fillRect(x + 4, y + 8, 12, 2, YELLOW);
388  tft.fillRect(x + 4, y + 10, 14, 2, YELLOW);
389  tft.fillRect(x + 4, y + 12, 16, 2, YELLOW);
390  tft.fillRect(x + 4, y + 14, 14, 2, YELLOW);
391  tft.fillRect(x + 4, y + 16, 12, 2, YELLOW);
392  tft.fillRect(x + 6, y + 18, 12, 2, YELLOW);
393  tft.fillRect(x + 10, y + 20, 10, 2, YELLOW);
394  tft.fillRect(x + 18, y + 2, 2, 2, BLACK);
395  tft.fillRect(x + 16, y + 4, 2, 6, BLACK);
396  tft.fillRect(x + 18, y + 10, 2, 2, BLACK);
397  tft.fillRect(x + 18, y + 4, 2, 6, WHITE);
398  tft.fillRect(x + 20, y + 2, 4, 10, WHITE);
399  tft.fillRect(x + 24, y + 4, 2, 8, WHITE);
400  tft.fillRect(x + 26, y + 6, 2, 6, WHITE);
401  tft.fillRect(x + 24, y + 6, 2, 4, BLACK);
402  tft.fillRect(x + 20, y + 12, 12, 2, BLACK);
403  tft.fillRect(x + 18, y + 14, 2, 2, BLACK);
404  tft.fillRect(x + 20, y + 14, 12, 2, RED);
405  tft.fillRect(x + 32, y + 14, 2, 2, BLACK);
406  tft.fillRect(x + 16, y + 16, 2, 2, BLACK);
407  tft.fillRect(x + 18, y + 16, 2, 2, RED);
408  tft.fillRect(x + 20, y + 16, 12, 2, BLACK);
409  tft.fillRect(x + 18, y + 18, 2, 2, BLACK);
410  tft.fillRect(x + 20, y + 18, 10, 2, RED);
411  tft.fillRect(x + 30, y + 18, 2, 2, BLACK);
412  tft.fillRect(x + 20, y + 20, 10, 2, BLACK);
413}
414
415void drawWing1(int x, int y) {
416  tft.fillRect(x, y + 14, 2, 6, BLACK);
417  tft.fillRect(x + 2, y + 20, 8, 2, BLACK);
418  tft.fillRect(x + 2, y + 12, 10, 2, BLACK);
419  tft.fillRect(x + 12, y + 14, 2, 2, BLACK);
420  tft.fillRect(x + 10, y + 16, 2, 2, BLACK);
421  tft.fillRect(x + 2, y + 14, 8, 6, WHITE);
422  tft.fillRect(x + 8, y + 18, 2, 2, BLACK);
423  tft.fillRect(x + 10, y + 14, 2, 2, WHITE);
424}
425
426void drawWing2(int x, int y) {
427  tft.fillRect(x + 2, y + 10, 10, 2, BLACK);
428  tft.fillRect(x + 2, y + 16, 10, 2, BLACK);
429  tft.fillRect(x, y + 12, 2, 4, BLACK);
430  tft.fillRect(x + 12, y + 12, 2, 4, BLACK);
431  tft.fillRect(x + 2, y + 12, 10, 4, WHITE);
432}
433
434void drawWing3(int x, int y) {
435  tft.fillRect(x + 2, y + 6, 8, 2, BLACK);
436  tft.fillRect(x, y + 8, 2, 6, BLACK);
437  tft.fillRect(x + 10, y + 8, 2, 2, BLACK);
438  tft.fillRect(x + 12, y + 10, 2, 4, BLACK);
439  tft.fillRect(x + 10, y + 14, 2, 2, BLACK);
440  tft.fillRect(x + 2, y + 14, 2, 2, BLACK);
441  tft.fillRect(x + 4, y + 16, 6, 2, BLACK);
442  tft.fillRect(x + 2, y + 8, 8, 6, WHITE);
443  tft.fillRect(x + 4, y + 14, 6, 2, WHITE);
444  tft.fillRect(x + 10, y + 10, 2, 4, WHITE);
445}
446
447void ResetScore() {
448  TSPoint p = safeGetPoint();
449  if (p.x < 199 && p.y < 293 && running == false && p.z > MINPRESSURE) {
450    EEPROM.write(addr, 0);  
451    startGame();    
452  }
453}
454
455void sensereset() {
456  TSPoint p = safeGetPoint();
457  if (p.x < 199 && p.y < 293 && !running && p.z > MINPRESSURE)
458    resetsensed = true;
459  else
460    resetsensed = false;
461}
462
463void startGame() {
464  flX = 50;
465  flY = 25;
466  fallRate = 0; 
467  pillarPos = 320;  
468  gapPosition = 60; 
469  crashed = false;  
470  score = 0;       
471  highScore = EEPROM.read(addr);    
472  tft.setFont(&Org_01);              
473  tft.fillScreen(SKYBLUE);              
474  tft.setTextColor(YELLOW);          
475  tft.setTextSize(3);                
476  tft.setCursor(5, 20);              
477  tft.println("Flappy Bird");
478  tft.setTextColor(WHITE);
479  tft.setTextSize(2);
480  tft.println(" Tap to begin!!");
481  tft.setTextColor(GREEN);
482  tft.setCursor(60, 60);
483  tft.print("Top Score : ");
484  tft.setTextColor(RED);
485  tft.setTextSize(3);
486  tft.print(highScore);
487  tft.setTextSize(2);
488  tft.fillRoundRect(240, 5, 250, 15, 8, WHITE);
489  tft.drawRoundRect(240, 5, 250, 15, 8, RED);
490  tft.setCursor(250, 15);
491  tft.println("RESET");
492
493  tft.fillRoundRect(240, 30, 250, 15, 8, WHITE);
494  tft.drawRoundRect(240, 30, 250, 15, 8, RED);
495  tft.setCursor(250, 40);
496  tft.print("BACK");
497
498  int ty = 230; int tx = 0;
499  for ( tx = 0; tx <= 300; tx += 20) {
500    tft.fillTriangle(tx, ty, tx + 10, ty, tx, ty + 10, GREEN);
501    tft.fillTriangle(tx + 10, ty + 10, tx + 10, ty, tx, ty + 10, YELLOW);
502    tft.fillTriangle(tx + 10, ty, tx + 20, ty, tx + 10, ty + 10, YELLOW);
503    tft.fillTriangle(tx + 20, ty + 10, tx + 20, ty, tx + 10, ty + 10, GREEN);
504  }
505  delay(1000);
506  nextDrawLoopRunTime = millis() + DRAW_LOOP_INTERVAL;
507}
508
509void senseBack() {
510  TSPoint p = safeGetPoint();
511  if (p.y < 305 && p.x < 285 && p.x > 239 && !running && p.z > MINPRESSURE) {
512    backsensed = true;
513  }
514  else
515    backsensed = false;
516}
517
518void drawrgb() {
519  tft.fillScreen(BLACK);
520  tft.setCursor(90, 20);
521  tft.setTextColor(WHITE);
522  tft.setTextSize(2);
523  tft.print("COLOUR : ");
524  tft.drawRect(BAR_MINY, BLUEBAR_MINX, BAR_HEIGHT, BAR_WIDTH, WHITE);  
525  tft.drawRect(BAR_MINY, GREENBAR_MINX, BAR_HEIGHT, BAR_WIDTH, WHITE);  
526  tft.drawRect(BAR_MINY, REDBAR_MINX, BAR_HEIGHT, BAR_WIDTH, WHITE); 
527  tft.fillRect(BAR_MINY + 12, REDBAR_MINX + 3, BAR_WIDTH - 10, BAR_WIDTH - 5, RED);
528  tft.fillRect(BAR_MINY + 12, GREENBAR_MINX + 3, BAR_WIDTH - 10, BAR_WIDTH - 5, GREEN);
529  tft.fillRect(BAR_MINY + 12, BLUEBAR_MINX + 3, BAR_WIDTH - 10, BAR_WIDTH - 5, BLUE);
530  tft.fillRoundRect(5, 5, 50, 30, 8, BLUE);
531  tft.drawRoundRect(5, 5, 50, 30, 8, WHITE);
532  tft.setCursor(15, 15);
533  tft.setTextColor(BLACK);
534  tft.print("<-");
535  delay(300);
536}
537
538void drawOSC() {
539  tft.fillScreen(BLACK);
540  tft.fillRoundRect(5, 5, 50, 30, 8, BLUE);
541  tft.drawRoundRect(5, 5, 50, 30, 8, WHITE);
542  tft.setCursor(15, 15);
543  tft.print("<-");
544}
TFT 2.4 inch display
Buy on Amazon
  • USB Cable
    Buy on Amazon