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
- Committer:
- Mpmart08
- Date:
- 2016-03-15
- Revision:
- 0:cd1d2540aaf4
File content as of revision 0:cd1d2540aaf4:
#include "mbed.h" #include "rtos.h" #include "PinDetect.h" #include "uLCD_4DGL.h" #include "Speaker.h" #include "SDFileSystem.h" #include "pipe.h" #include "bird.h" #include "soundBuilder.h" #include <stdlib.h> // image sectors on ulcd sd card #define BACKGROUND 0x0000, 0x0000 // background #define FLAPPY 0x0000, 0x0041 // bird #define PIPEUP 0x0000, 0x0043 // pipe pointing up #define PIPEDOWN16 0x0000, 0x0054 // pipe pointing down with a height of 16 #define PIPEDOWN32 0x0000, 0x0057 // pipe pointing down with a height of 32 #define PIPEDOWN48 0x0000, 0x005C // pipe pointing down with a height of 48 #define PIPEDOWN64 0x0000, 0x0063 // pipe pointing down with a height of 64 #define PIPEDOWN80 0x0000, 0x006C // pipe pointing down with a height of 80 #define PIPEDOWN96 0x0000, 0x0077 // pipe pointing down with a height of 96 // Nav Switch PinDetect nsUp(p16); // up button PinDetect nsCenter(p15); // center button PinDetect nsDown(p13); // down button // uLCD uLCD_4DGL uLCD(p28, p27, p30); // Speaker Speaker mySpeaker(p25); // SD File System SDFileSystem sd(p5, p6, p7, p8, "sd"); // Potentiometer AnalogIn pot(p20); // Bird Bird flappyBird; // Pipe Pipe pipe; int score = 0; int oldScore = 0; int gameSpeed = 0; // State machine definitions enum gameStateType {START, WAIT, GAME_SETUP, GAME, LOSE}; /* State Definitions: * START -- Creates the start screen * WAIT -- After the start screen, goes into wait where mbed waits for player to start the game * GAME_SETUP -- Initializes game objects such as the bird and pipe * GAME -- When the user actually gets to play * LOSE -- clears the screen, prints you lose and if you get a high score, stores it, then goes back to start */ // Global state machine variable gameStateType gameState = START; // function that draws each frame of the game on the lcd void drawScreen() { // clears the pipe from its previous location uLCD.filled_rectangle( // draws a rectangle the size of the pipe pipe.getOldX(), // the pipe's old x position 0, // the top of the screen pipe.getOldX() + pipe.getWidth(), // the pipe's old x position + the pipe's width 127, // the bottom of the screen 0x4EC0CA // the color of the background ); // draws the lower pipe at its current location uLCD.set_sector_address(PIPEUP); int x = pipe.getX(); int y = pipe.getY() + 32; uLCD.display_image(x,y); // draws the upper pipe at its current location switch (pipe.getType()) { case PIPE16: uLCD.set_sector_address(PIPEDOWN16); break; case PIPE32: uLCD.set_sector_address(PIPEDOWN32); break; case PIPE48: uLCD.set_sector_address(PIPEDOWN48); break; case PIPE64: uLCD.set_sector_address(PIPEDOWN64); break; case PIPE80: uLCD.set_sector_address(PIPEDOWN80); break; case PIPE96: uLCD.set_sector_address(PIPEDOWN96); break; } x = pipe.getX(); y = 0; uLCD.display_image(x,y); // clears the bird from its previous location uLCD.filled_rectangle( // draws a rectangle the size of the bird flappyBird.getX(), // the bird's current x position flappyBird.getOldY(), // the bird's old y position flappyBird.getX() + flappyBird.getWidth(), // the bird's x position + the bird's width flappyBird.getOldY() + flappyBird.getHeight(), // the bird's old y position + the bird's height 0x4EC0CA // the color of the background ); // draws the bird at its current location uLCD.set_sector_address(FLAPPY); x = flappyBird.getX(); y = flappyBird.getY(); uLCD.display_image(x,y); // prints the player's current score uLCD.locate(1,1); uLCD.printf("%d", score); } // function that determines if the bird has collided with a pipe bool checkCollision() { if (pipe.getX() <= flappyBird.getX() + flappyBird.getWidth() && flappyBird.getX() <= pipe.getX() + pipe.getWidth()) { return (flappyBird.getY() < pipe.getY() || flappyBird.getY() >= (pipe.getY() + 32)); } else { return false; } } // Nav switch callbacks void nsUp_hit_callback() // the up button is pressed { switch (gameState) { case GAME: // if game is running, then move the bird upwards flappyBird.move(DIRECTION_UP); break; } } void nsDown_hit_callback() // the down button is pressed { switch (gameState) { case GAME: // if game is running, then move the bird downwards flappyBird.move(DIRECTION_DOWN); break; } } void nsCenter_hit_callback() // the center button is pressed { switch (gameState) { case WAIT: // if game is waiting to start, set up the game gameState = GAME_SETUP; break; } } // thread that plays game sounds through the speaker void speaker_thread(void const *argument) { Speaker *player = &mySpeaker; // Start Song float sFreq[] = {550,750,550,750}; float sDur[] = {.3,.3,.3,.3}; float sVol[] = {.5,.5,.5,.5}; SoundBuilder startSong(sFreq, sDur, sVol, sizeof(sFreq)/sizeof(*sFreq), player); // End Song float eFreq[] = {300,200,250,225,200,150,150,100}; float eDur[] = {.3,.3,.3,.3,.3,.3,.3,.3}; float eVol[] = {.5,.5,.5,.5,.5,.5,.5,.5}; SoundBuilder endSong(eFreq, eDur, eVol, sizeof(eFreq)/sizeof(*eFreq), player); while (true) { switch (gameState) { case GAME: // if game is running and user dodges a pipe, play a note if (oldScore < score) { mySpeaker.PlayNote(440, 0.1, 0.5); oldScore = score; } break; case START: // play a song at the start of the game startSong.playSong(); break; case LOSE: // play a song when the player loses the game endSong.playSong(); wait(5); break; } } } int main() { // Setup internal pullup resistors for nav switch input pins nsUp.mode(PullUp); nsDown.mode(PullUp); nsCenter.mode(PullUp); // Wait for pullup to take effect wait(0.1); // Attaches nav switch inputs to the callback functions nsUp.attach_deasserted(&nsUp_hit_callback); nsDown.attach_deasserted(&nsDown_hit_callback); nsCenter.attach_deasserted(&nsCenter_hit_callback); // Set sample frequency for nav switch interrupts nsUp.setSampleFrequency(); nsDown.setSampleFrequency(); nsCenter.setSampleFrequency(); // initialize the lcd uLCD.media_init(); uLCD.cls(); uLCD.background_color(0x4EC0CA); uLCD.textbackground_color(0x4EC0CA); uLCD.color(WHITE); int highscore = 0; // variable to store high score int i = 0; // variable for seeding random pipe generation Thread thread1(speaker_thread); // start speaker thread while (1) { switch (gameState) { case START: // read current high score from a text file on the sd card FILE *fp = fopen("/sd/highscore.txt", "r"); if(fp == NULL) { error("Could not open file for read\n"); } fscanf(fp, "%i", &highscore); fclose(fp); // display start screen on lcd uLCD.cls(); uLCD.locate(0,0); uLCD.printf("Flappy Bird(ish)!\n\n"); uLCD.printf("Press Fire\nto Start\n\n"); uLCD.printf("High Score: %i", highscore); gameState = WAIT; break; case GAME_SETUP: // initialize game objects and draw initial frame on the lcd uLCD.cls(); pipe = Pipe(); drawScreen(); srand(i); score = 0; oldScore = 0; gameState = GAME; break; case GAME: // read the game speed from the potentiometer gameSpeed = (int) (pot + 1) * 5; // if there is a collision, the player loses if (checkCollision()) { gameState = LOSE; } // if the player dodges a pipe, increase the score and create a new pipe if (pipe.getX() + pipe.getWidth() < 0) { score++; pipe = Pipe(); } // draw the current frame of the game on the lcd drawScreen(); // move the pipe across the screen according the game speed pipe.move(gameSpeed); // wait for lcd to finish drawing images wait(0.25); break; case LOSE: // display game over screen on lcd uLCD.cls(); uLCD.printf("YOU LOSE D:\n\n"); // if the user beat the high score, save and display high score info if (score > highscore){ uLCD.printf("CONGRATZ THO NEW HIGH SCORE!"); uLCD.printf(" %i", score); // overwrite previous high score fp = fopen("/sd/highscore.txt", "w"); fprintf(fp, "%i", score); fclose(fp); } // restart game after 5 seconds wait(5.0); gameState = START; break; case WAIT: i++; // Used to seed the rand() function so we don't get the same positions for the pipes every time break; } } }