a flappy bird game demo of the RA8875 display library.
I came across some code for a flappy bird game at www.HowToMechatronics.com. It might entertain little kids for a while, so I did a quick port from arduino to mbed and for the RA8875 display library.
main.cpp
- Committer:
- WiredHome
- Date:
- 2020-03-29
- Revision:
- 7:39363a4f6255
- Parent:
- 5:f1fe5ccc4d5b
File content as of revision 7:39363a4f6255:
/* Arduino Game Proejct * Program made by Dejan Nedelkovski, * www.HowToMechatronics.com * * Adapted to the RA8875 and mbed by David Smart * * Possible Improvements: * - create an in-ram image of the bird(s) and blit them. * - use 2-layers and transparency. Put the bird and pillar in front of the sky * - use block-move for the bird and the sky * - tune the easy/hard configuration values a little more. */ #include "mbed.h" // Last tested: v122 #include "RA8875.h" // Last tested: v125 // Define this for 800x480 panel, undefine for 480x272 #define BIG_SCREEN // Define this for Cap touch panel, undefine for resistive #define CAP_TOUCH #ifdef CAP_TOUCH RA8875 myGLCD(p5, p6, p7, p12, NC, p9,p10,p13, "tft"); // SPI:{MOSI,MISO,SCK,/ChipSelect,/reset}, I2C:{SDA,SCL,/IRQ}, name #else RA8875 myGLCD(p5, p6, p7, p12, NC, "tft"); // SPI:{MOSI,MISO,SCK,/ChipSelect,/reset}, name #endif #define PC_BAUD 460800 // I like the serial communications to be very fast // // // // // // // // // // // // // // // // // // // // // // // // // End of Configuration Section // // // // // // // // // // // // // // // // // // // // // // // // LocalFileSystem local("local"); // access to calibration file for resistive touch. Serial pc(USBTX, USBRX); // Not required for display #ifdef BIG_SCREEN #define LCD_W 800 #define LCD_H 480 #define LCD_C 8 // color - bits per pixel #define DEF_RADIUS 50 // default radius of the fingerprint #define BL_NORM 25 // Backlight Normal setting (0 to 255) #else #define LCD_W 480 #define LCD_H 272 #define LCD_C 8 // color - bits per pixel #define DEF_RADIUS 20 // default radius of the fingerprint #define BL_NORM 25 // Backlight Normal setting (0 to 255) #endif // +----------------------------------------------------------------+------+--------+ // | | | | // | | | | // | (x,y) |Pillar| | // | +------+ +-----------------------+ +------+ | // | | Bird h | Tap To Start Easy | (x,y) ^ | // | +---w--+ +-----------------------+ window | // | h | // | +-----------------------+ v | // | | Tap To Start Hard | +---w--+ | // | +-----------------------+ | | | // | | | | // | | | | // | | | | // | | | | // | | | | // | | | | // +----------------------------------------------------------------+------+--------+ Ground // | From HowToMechatronics.com Adapted by Smartware Computing | // +--------------------------------------------------------------------------------+ ScoreZone // | S C O R E : # # # Highest Score: ##### [Reset] | // | Highest Score: ##### | // +--------------------------------------------------------------------------------+ // + // INFO_X #define INFO_X (300) #define GROUND_Y (LCD_H - 60) #define SCOREZONE_Y (LCD_H - 40) #define BIRD_W 35 #define BIRD_H 30 #define BIRD_X 50 #define BIRD_Y 50 #define TAP_EASY_Y (GROUND_Y/2 - 64) #define TAP_EASY_MSG "TAP TO START EASY GAME" // 22 chars #define TAP_HARD_Y (GROUND_Y/2 - 0) #define TAP_HARD_MSG "TAP TO START HARD GAME" // 22 chars #define TAP_LEN 22 // 22 chars #define TAP_W 16*TAP_LEN #define TAP_H 32 #define TAP_X (LCD_W/2 - 16*TAP_LEN/2) // text centered on screen #define RESET_X (LCD_W - 2 - 160) #define RESET_Y SCOREZONE_Y #define RESET_W (160) #define RESET_H (LCD_H - 1 - SCOREZONE_Y) #define PILLAR_W 50 #define WINDOW_H_EASY 120 #define WINDOW_H_HARD 80 #define COLOR_SKY RGB(114, 198, 206) #define COLOR_GROUND RGB(64,248,48) #define COLOR_SCOREZONE RGB(221, 216, 148) #define COLOR_PILLAR RGB(0, 200, 20) const rect_t r_easy = rect_t ( TAP_X,TAP_EASY_Y, TAP_X+TAP_W, TAP_EASY_Y+TAP_H ); const rect_t r_hard = rect_t ( TAP_X,TAP_HARD_Y, TAP_X+TAP_W, TAP_HARD_Y+TAP_H ); const rect_t r_Reset = rect_t ( RESET_X,RESET_Y, RESET_X+RESET_W,RESET_Y+RESET_H ); const rect_t r_Ground = rect_t ( 1,GROUND_Y, LCD_W-4,SCOREZONE_Y-1 ); const rect_t r_Score = rect_t ( 1,SCOREZONE_Y, LCD_W-4,LCD_H-3 ); const rect_t r_PlayField = rect_t ( 0,0, LCD_W-1, GROUND_Y-1 ); rect_t r_Bird = rect_t ( BIRD_X,BIRD_Y, BIRD_X+BIRD_W,BIRD_Y+BIRD_H ); rect_t r_PillarUp = rect_t ( 0,0, 0+PILLAR_W,GROUND_Y/4 ); rect_t r_PillarDn = rect_t ( 0,GROUND_Y/4, 0+PILLAR_W,GROUND_Y-1 ); int movingRate = 3; int fallRateInt = 0; float fallRate = 0; int score = 0; int lastSpeedUpScore = 0; #define SPEED_UP_EASY 5 #define SPEED_UP_HARD 2 int speed_up_threshold = SPEED_UP_EASY; int highestScore; bool screenPressed = false; bool gameStarted = false; Timer timer; int lastPillarTime; int pillarStepTime = 30; // 50 mSec time between pillar motion to start. int lastBirdTime; int birdStepTime = 60; int window_h = WINDOW_H_EASY; void initiateGame(); void SetPillarX(int x); void SetWindowY(int y); void SetBirdY(int y); void DrawPillars(); void DrawBird(); void gameOver(); void setup() { myGLCD.cls(); timer.start(); highestScore = 0; //EEPROM.read(0); // Read the highest score from the EEPROM initiateGame(); // Initiate the game } void loop() { int nowTime = timer.read_ms(); if ((nowTime - lastPillarTime) > pillarStepTime) { lastPillarTime = nowTime; SetPillarX(r_PillarUp.p1.x - movingRate); DrawPillars(); // Draws the pillars } if ((nowTime - lastBirdTime) > birdStepTime) { lastBirdTime = nowTime; SetBirdY(r_Bird.p1.y + fallRateInt); DrawBird(); // Draws the bird 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 (r_Bird.p2.y >= (GROUND_Y - 1 ) || r_Bird.p1.y <= 0) { // top and bottom gameOver(); } if (myGLCD.Intersect(r_Bird, r_PillarUp) || myGLCD.Intersect(r_Bird, r_PillarDn)) { gameOver(); } // After the pillar has passed through the screen if (r_PillarUp.p2.x <= 0) { SetPillarX(LCD_W - 2); SetWindowY(rand() % (GROUND_Y - window_h)); // Random number for the pillars height score++; // Increase score by one } //==== Controlling the bird point_t p; if (myGLCD.TouchPanelReadable(&p) && !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 ( !myGLCD.TouchPanelReadable() && screenPressed) { screenPressed = false; } // After each few points, increases the moving rate of the pillars if ((score - lastSpeedUpScore) == speed_up_threshold) { lastSpeedUpScore = score; movingRate++; } } void DrawScore(void) { myGLCD.foreground(Black); myGLCD.background(COLOR_SCOREZONE); myGLCD.SetTextFontSize(2); myGLCD.SetTextCursor(5,SCOREZONE_Y); myGLCD.printf("Score: %5d", score); } void DrawHighScore(void) { myGLCD.SetTextFontSize(2); myGLCD.SetTextCursor(INFO_X,SCOREZONE_Y); myGLCD.printf("Highest: %5d", highestScore); } void ShowReset(bool showit) { myGLCD.background(COLOR_SCOREZONE); myGLCD.rect(r_Reset, COLOR_SCOREZONE); if (showit) { myGLCD.foreground(Black); myGLCD.SetTextCursor(RESET_X,RESET_Y); myGLCD.SetTextFontSize(2); myGLCD.printf(">RESET<"); } } // ===== initiateGame - Custom Function void initiateGame() { SetPillarX(LCD_W - PILLAR_W - 30); SetWindowY(rand() % (GROUND_Y - window_h)); SetBirdY(BIRD_Y); fallRate = 0; score = 0; lastSpeedUpScore = 0; movingRate = 3; // Blue sky myGLCD.foreground(White); myGLCD.background(COLOR_SKY); myGLCD.cls(); // Ground myGLCD.fillrect(r_Ground, COLOR_GROUND); myGLCD.foreground(Black); myGLCD.background(COLOR_GROUND); myGLCD.SetTextFontSize(1); myGLCD.SetTextCursor(5,GROUND_Y); myGLCD.printf("From www.HowToMechatronics.com"); myGLCD.SetTextCursor(INFO_X,GROUND_Y); myGLCD.printf("Adapted for RA8875 and mbed by Smartware Computing"); // ScoreZone myGLCD.fillrect(r_Score, COLOR_SCOREZONE); DrawScore(); DrawHighScore(); ShowReset(true); // Start buttons myGLCD.SetTextCursor(r_easy.p1); myGLCD.SetTextFontSize(2); myGLCD.foreground(Black); myGLCD.printf(TAP_EASY_MSG); myGLCD.rect(r_easy, BrightRed); myGLCD.SetTextCursor(r_hard.p1); myGLCD.SetTextFontSize(2); myGLCD.foreground(Black); myGLCD.printf(TAP_HARD_MSG); myGLCD.rect(r_hard, BrightRed); wait(0.5); DrawBird(); // Draws the bird DrawPillars(); // Wait until we tap the sreen while (!gameStarted) { point_t p; if (myGLCD.TouchPanelReadable(&p)) { if (myGLCD.Intersect(r_Reset, p)) { highestScore = 0; myGLCD.fillrect(r_Reset, COLOR_SCOREZONE); DrawHighScore(); } if (myGLCD.Intersect(r_easy,p)) { movingRate = 3; window_h = WINDOW_H_EASY; speed_up_threshold = SPEED_UP_EASY; gameStarted = true; } if (myGLCD.Intersect(r_hard,p)) { movingRate = 8; window_h = WINDOW_H_HARD; speed_up_threshold = SPEED_UP_HARD; gameStarted = true; } } } ShowReset(false); myGLCD.fillrect(r_easy, COLOR_SKY); myGLCD.fillrect(r_hard, COLOR_SKY); wait(0.5); lastBirdTime = lastPillarTime = timer.read_ms(); } // ===== DrawPillars - Custom Function // (x,y) is the bottom left of the top pillar // // Set the left side of the pillar void SetPillarX(int x) { r_PillarUp.p1.x = r_PillarDn.p1.x = x; r_PillarUp.p2.x = r_PillarDn.p2.x = x + PILLAR_W; } void SetWindowY(int y) { r_PillarUp.p2.y = y; r_PillarDn.p1.y = y + window_h; } void DrawPillars() { rect_t r; for (int i=0; i<2; i++) { r = (i == 0) ? r_PillarUp : r_PillarDn; myGLCD.Intersect(&r, &r_PlayField); // Create a new rect that fits on the screen myGLCD.fillrect(r, COLOR_PILLAR); myGLCD.rect(r, Black); r.p1.x = r.p2.x + 1; // Sky-fill to the right of the pillar r.p2.x += movingRate; if (myGLCD.Intersect(&r, &r_PlayField)) { myGLCD.fillrect(r, COLOR_SKY); } } DrawScore(); } void SetBirdY(int y) { r_Bird.p1.y = y; if (r_Bird.p1.y + BIRD_H >= GROUND_Y) r_Bird.p1.y = GROUND_Y - BIRD_H - 1; r_Bird.p2.y = y + BIRD_H; } void DrawBird() { #if 1 point_t p; rect_t r; r = r_Bird; // Clear space above or below if (fallRateInt > 0) { // Falling r.p1.y -= fallRateInt; if (r.p1.y < 0) r.p1.y = 0; } else if (fallRateInt < 0) { // Rising r.p2.y += -fallRateInt; if (r.p2.y >= GROUND_Y) r.p2.y = GROUND_Y - 1; } myGLCD.fillrect(r, COLOR_SKY); // erase old bird // center body p.x = r_Bird.p1.x + BIRD_W/2; p.y = r_Bird.p1.y + BIRD_H/2; myGLCD.fillcircle(p, 7*BIRD_H/16, (color_t)(RGB(255,255,0))); p.x = r_Bird.p1.x + 3*BIRD_W/4; p.y = r_Bird.p1.y + 1*BIRD_H/4; myGLCD.fillcircle(p, BIRD_H/5, White); myGLCD.circle(p, BIRD_H/5, Black); myGLCD.fillcircle(p, BIRD_H/8, Black); // Beak r.p1.x = r_Bird.p1.x + 9*BIRD_W/16; r.p1.y = r_Bird.p1.y + BIRD_H/2; r.p2.x = r_Bird.p1.x + BIRD_W; r.p2.y = r.p1.y + BIRD_H/5; myGLCD.fillroundrect(r, 3, 3, BrightRed); myGLCD.roundrect(r, 3, 3, Black); // Wing up/down if (fallRate > 0) { r.p1.y -= BIRD_H/6; r.p2.y = r.p1.y + BIRD_H/5; } else if (fallRate < 0) { r.p1.y += BIRD_H/6; r.p2.y = r.p1.y + BIRD_H/5; } r.p1.x = r_Bird.p1.x; r.p2.x = r.p1.x + 3*BIRD_W/8; myGLCD.fillroundrect(r, 3, 3, White); myGLCD.roundrect(r, 3, 3, Black); #else //printf("DrawBird(%d)\r\n", y); RetCode_t r = myGLCD.RenderImageFile(BIRD_X, y, "/local/BIRD_01.jpg"); // 35x30 myGLCD.fillrect(BIRD_X,y,BIRD_X+BIRD_W,y-fallRateInt, COLOR_SKY); // Draws blue rectangles above and below the bird myGLCD.fillrect(BIRD_X,y+BIRD_H,BIRD_X+BIRD_W,y+BIRD_H+fallRateInt, COLOR_SKY); // in order to clear its previous state #endif } //======== gameOver() - Custom Function void gameOver() { wait(3.000); // Clears the screen and prints the text //myGLCD.cls(); myGLCD.foreground(RGB(255, 255, 255)); myGLCD.background(RGB(0, 0, 0)); myGLCD.SetTextFontSize(2); myGLCD.SetTextCursor(INFO_X, 40); myGLCD.printf("GAME OVER"); DrawScore(); myGLCD.SetTextCursor(INFO_X,120); myGLCD.printf("Restarting..."); myGLCD.SetTextFontSize(2); for (int i=5; i>0; i--) { myGLCD.SetTextCursor(INFO_X,150); myGLCD.printf("%d", i); wait(1.000); } // Writes the highest score in the EEPROM if (score > highestScore) { highestScore = score; //EEPROM.write(0,highestScore); } // Resets the variables to start position values gameStarted = false; initiateGame(); } int main(void) { pc.baud(PC_BAUD); //I like a snappy terminal, so crank it up! pc.printf("\r\nFlappy Bird - Build " __DATE__ " " __TIME__ "\r\n"); myGLCD.init((LCD_W-2),LCD_H,LCD_C); myGLCD.TouchPanelInit(); myGLCD.Backlight_u8(BL_NORM); setup(); while(1) { loop(); } }