Flappy Bird game on mbed with a micro LCD screen, class D amp, speaker, SD card reader/writer, 5-button navigation switch, and potentiometer speed control
Dependencies: 4DGL-uLCD-SE PinDetect SDFileSystem mbed-rtos mbed
main.cpp
00001 #include "mbed.h" 00002 #include "rtos.h" 00003 #include "PinDetect.h" 00004 #include "uLCD_4DGL.h" 00005 #include "Speaker.h" 00006 #include "SDFileSystem.h" 00007 #include "pipe.h" 00008 #include "bird.h" 00009 #include "soundBuilder.h" 00010 #include <stdlib.h> 00011 00012 // image sectors on ulcd sd card 00013 #define BACKGROUND 0x0000, 0x0000 // background 00014 #define FLAPPY 0x0000, 0x0041 // bird 00015 #define PIPEUP 0x0000, 0x0043 // pipe pointing up 00016 #define PIPEDOWN16 0x0000, 0x0054 // pipe pointing down with a height of 16 00017 #define PIPEDOWN32 0x0000, 0x0057 // pipe pointing down with a height of 32 00018 #define PIPEDOWN48 0x0000, 0x005C // pipe pointing down with a height of 48 00019 #define PIPEDOWN64 0x0000, 0x0063 // pipe pointing down with a height of 64 00020 #define PIPEDOWN80 0x0000, 0x006C // pipe pointing down with a height of 80 00021 #define PIPEDOWN96 0x0000, 0x0077 // pipe pointing down with a height of 96 00022 00023 // Nav Switch 00024 PinDetect nsUp(p16); // up button 00025 PinDetect nsCenter(p15); // center button 00026 PinDetect nsDown(p13); // down button 00027 00028 // uLCD 00029 uLCD_4DGL uLCD(p28, p27, p30); 00030 00031 // Speaker 00032 Speaker mySpeaker(p25); 00033 00034 // SD File System 00035 SDFileSystem sd(p5, p6, p7, p8, "sd"); 00036 00037 // Potentiometer 00038 AnalogIn pot(p20); 00039 00040 // Bird 00041 Bird flappyBird; 00042 00043 // Pipe 00044 Pipe pipe; 00045 00046 int score = 0; 00047 int oldScore = 0; 00048 int gameSpeed = 0; 00049 00050 // State machine definitions 00051 enum gameStateType {START, WAIT, GAME_SETUP, GAME, LOSE}; 00052 /* State Definitions: 00053 * START -- Creates the start screen 00054 * WAIT -- After the start screen, goes into wait where mbed waits for player to start the game 00055 * GAME_SETUP -- Initializes game objects such as the bird and pipe 00056 * GAME -- When the user actually gets to play 00057 * LOSE -- clears the screen, prints you lose and if you get a high score, stores it, then goes back to start 00058 */ 00059 00060 // Global state machine variable 00061 gameStateType gameState = START; 00062 00063 // function that draws each frame of the game on the lcd 00064 void drawScreen() { 00065 00066 // clears the pipe from its previous location 00067 uLCD.filled_rectangle( // draws a rectangle the size of the pipe 00068 pipe.getOldX(), // the pipe's old x position 00069 0, // the top of the screen 00070 pipe.getOldX() + pipe.getWidth(), // the pipe's old x position + the pipe's width 00071 127, // the bottom of the screen 00072 0x4EC0CA // the color of the background 00073 ); 00074 00075 // draws the lower pipe at its current location 00076 uLCD.set_sector_address(PIPEUP); 00077 int x = pipe.getX(); 00078 int y = pipe.getY() + 32; 00079 uLCD.display_image(x,y); 00080 00081 // draws the upper pipe at its current location 00082 switch (pipe.getType()) { 00083 case PIPE16: 00084 uLCD.set_sector_address(PIPEDOWN16); 00085 break; 00086 case PIPE32: 00087 uLCD.set_sector_address(PIPEDOWN32); 00088 break; 00089 case PIPE48: 00090 uLCD.set_sector_address(PIPEDOWN48); 00091 break; 00092 case PIPE64: 00093 uLCD.set_sector_address(PIPEDOWN64); 00094 break; 00095 case PIPE80: 00096 uLCD.set_sector_address(PIPEDOWN80); 00097 break; 00098 case PIPE96: 00099 uLCD.set_sector_address(PIPEDOWN96); 00100 break; 00101 } 00102 x = pipe.getX(); 00103 y = 0; 00104 uLCD.display_image(x,y); 00105 00106 // clears the bird from its previous location 00107 uLCD.filled_rectangle( // draws a rectangle the size of the bird 00108 flappyBird.getX(), // the bird's current x position 00109 flappyBird.getOldY(), // the bird's old y position 00110 flappyBird.getX() + flappyBird.getWidth(), // the bird's x position + the bird's width 00111 flappyBird.getOldY() + flappyBird.getHeight(), // the bird's old y position + the bird's height 00112 0x4EC0CA // the color of the background 00113 ); 00114 00115 // draws the bird at its current location 00116 uLCD.set_sector_address(FLAPPY); 00117 x = flappyBird.getX(); 00118 y = flappyBird.getY(); 00119 uLCD.display_image(x,y); 00120 00121 // prints the player's current score 00122 uLCD.locate(1,1); 00123 uLCD.printf("%d", score); 00124 } 00125 00126 // function that determines if the bird has collided with a pipe 00127 bool checkCollision() { 00128 00129 if (pipe.getX() <= flappyBird.getX() + flappyBird.getWidth() 00130 && flappyBird.getX() <= pipe.getX() + pipe.getWidth()) { 00131 return (flappyBird.getY() < pipe.getY() || flappyBird.getY() >= (pipe.getY() + 32)); 00132 } else { 00133 return false; 00134 } 00135 } 00136 00137 // Nav switch callbacks 00138 00139 void nsUp_hit_callback() // the up button is pressed 00140 { 00141 switch (gameState) 00142 { 00143 case GAME: // if game is running, then move the bird upwards 00144 flappyBird.move(DIRECTION_UP); 00145 break; 00146 } 00147 } 00148 00149 void nsDown_hit_callback() // the down button is pressed 00150 { 00151 switch (gameState) 00152 { 00153 case GAME: // if game is running, then move the bird downwards 00154 flappyBird.move(DIRECTION_DOWN); 00155 break; 00156 } 00157 } 00158 00159 void nsCenter_hit_callback() // the center button is pressed 00160 { 00161 switch (gameState) 00162 { 00163 case WAIT: // if game is waiting to start, set up the game 00164 gameState = GAME_SETUP; 00165 break; 00166 } 00167 } 00168 00169 // thread that plays game sounds through the speaker 00170 void speaker_thread(void const *argument) { 00171 00172 Speaker *player = &mySpeaker; 00173 00174 // Start Song 00175 float sFreq[] = {550,750,550,750}; 00176 float sDur[] = {.3,.3,.3,.3}; 00177 float sVol[] = {.5,.5,.5,.5}; 00178 SoundBuilder startSong(sFreq, sDur, sVol, sizeof(sFreq)/sizeof(*sFreq), player); 00179 00180 // End Song 00181 float eFreq[] = {300,200,250,225,200,150,150,100}; 00182 float eDur[] = {.3,.3,.3,.3,.3,.3,.3,.3}; 00183 float eVol[] = {.5,.5,.5,.5,.5,.5,.5,.5}; 00184 SoundBuilder endSong(eFreq, eDur, eVol, sizeof(eFreq)/sizeof(*eFreq), player); 00185 00186 while (true) { 00187 switch (gameState) { 00188 case GAME: // if game is running and user dodges a pipe, play a note 00189 if (oldScore < score) { 00190 mySpeaker.PlayNote(440, 0.1, 0.5); 00191 oldScore = score; 00192 } 00193 break; 00194 case START: // play a song at the start of the game 00195 startSong.playSong(); 00196 break; 00197 case LOSE: // play a song when the player loses the game 00198 endSong.playSong(); 00199 wait(5); 00200 break; 00201 } 00202 } 00203 } 00204 00205 int main() { 00206 00207 // Setup internal pullup resistors for nav switch input pins 00208 nsUp.mode(PullUp); 00209 nsDown.mode(PullUp); 00210 nsCenter.mode(PullUp); 00211 // Wait for pullup to take effect 00212 wait(0.1); 00213 // Attaches nav switch inputs to the callback functions 00214 nsUp.attach_deasserted(&nsUp_hit_callback); 00215 nsDown.attach_deasserted(&nsDown_hit_callback); 00216 nsCenter.attach_deasserted(&nsCenter_hit_callback); 00217 // Set sample frequency for nav switch interrupts 00218 nsUp.setSampleFrequency(); 00219 nsDown.setSampleFrequency(); 00220 nsCenter.setSampleFrequency(); 00221 00222 // initialize the lcd 00223 uLCD.media_init(); 00224 uLCD.cls(); 00225 uLCD.background_color(0x4EC0CA); 00226 uLCD.textbackground_color(0x4EC0CA); 00227 uLCD.color(WHITE); 00228 00229 int highscore = 0; // variable to store high score 00230 int i = 0; // variable for seeding random pipe generation 00231 00232 Thread thread1(speaker_thread); // start speaker thread 00233 00234 while (1) 00235 { 00236 switch (gameState) 00237 { 00238 case START: 00239 00240 // read current high score from a text file on the sd card 00241 FILE *fp = fopen("/sd/highscore.txt", "r"); 00242 if(fp == NULL) { 00243 error("Could not open file for read\n"); 00244 } 00245 fscanf(fp, "%i", &highscore); 00246 fclose(fp); 00247 00248 // display start screen on lcd 00249 uLCD.cls(); 00250 uLCD.locate(0,0); 00251 uLCD.printf("Flappy Bird(ish)!\n\n"); 00252 uLCD.printf("Press Fire\nto Start\n\n"); 00253 uLCD.printf("High Score: %i", highscore); 00254 gameState = WAIT; 00255 break; 00256 00257 case GAME_SETUP: 00258 00259 // initialize game objects and draw initial frame on the lcd 00260 uLCD.cls(); 00261 pipe = Pipe(); 00262 drawScreen(); 00263 srand(i); 00264 score = 0; 00265 oldScore = 0; 00266 gameState = GAME; 00267 break; 00268 00269 case GAME: 00270 00271 // read the game speed from the potentiometer 00272 gameSpeed = (int) (pot + 1) * 5; 00273 00274 // if there is a collision, the player loses 00275 if (checkCollision()) { 00276 gameState = LOSE; 00277 } 00278 00279 // if the player dodges a pipe, increase the score and create a new pipe 00280 if (pipe.getX() + pipe.getWidth() < 0) { 00281 score++; 00282 pipe = Pipe(); 00283 } 00284 00285 // draw the current frame of the game on the lcd 00286 drawScreen(); 00287 00288 // move the pipe across the screen according the game speed 00289 pipe.move(gameSpeed); 00290 00291 // wait for lcd to finish drawing images 00292 wait(0.25); 00293 break; 00294 00295 case LOSE: 00296 00297 // display game over screen on lcd 00298 uLCD.cls(); 00299 uLCD.printf("YOU LOSE D:\n\n"); 00300 00301 // if the user beat the high score, save and display high score info 00302 if (score > highscore){ 00303 uLCD.printf("CONGRATZ THO NEW HIGH SCORE!"); 00304 uLCD.printf(" %i", score); 00305 // overwrite previous high score 00306 fp = fopen("/sd/highscore.txt", "w"); 00307 fprintf(fp, "%i", score); 00308 fclose(fp); 00309 } 00310 00311 // restart game after 5 seconds 00312 wait(5.0); 00313 gameState = START; 00314 break; 00315 case WAIT: 00316 00317 i++; // Used to seed the rand() function so we don't get the same positions for the pipes every time 00318 break; 00319 } 00320 } 00321 }
Generated on Tue Jul 19 2022 06:40:37 by 1.7.2