Flappy Bird game: save high score to a file.

This commit is contained in:
Serge Vakulenko
2015-11-23 13:41:13 -08:00
parent f3f28ceca5
commit 76cb491c09

View File

@@ -1,6 +1,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/gpanel.h>
#include <sys/time.h>
#ifdef CROSS
@@ -25,7 +26,12 @@
/*
* Redraw every 50 msec
*/
#define DRAW_LOOP_INTERVAL 50
#define DRAW_LOOP_INTERVAL 50
/*
* File name for saving the high score.
*/
#define SCORE_FILENAME "flappy.score"
/*
* Data from external font files.
@@ -34,14 +40,14 @@ extern const struct gpanel_font_t font_lucidasans15;
extern const struct gpanel_font_t font_lucidasans28;
int wing;
int fx, fy, fallRate;
int pillarPos, gapPos;
int fx, fy, fall_rate;
int pillar_pos, gap_pos;
int score;
int highScore = 0;
int high_score = 0;
int running = 0;
int crashed = 0;
int scrPress = 0;
time_t nextDrawLoopRunTime;
int scr_press = 0;
time_t next_draw_time;
void rect(int color, int x, int y, int w, int h)
{
@@ -53,7 +59,7 @@ void fill(int color, int x, int y, int w, int h)
gpanel_fill(color, x, y, x+w-1, y+h-1);
}
void drawPillar(int x, int gap)
void draw_pillar(int x, int gap)
{
if (x >= 320)
return;
@@ -67,25 +73,25 @@ void drawPillar(int x, int gap)
rect(BLACK, x+1, gap+91, 48, 138-gap);
}
void clearPillar(int x, int gap)
void clear_pillar(int x, int gap)
{
if (x >= 320)
return;
// "cheat" slightly and just clear the right hand pixels
// to help minimise flicker, the rest will be overdrawn
/* "Cheat" slightly and just clear the right hand pixels
* to help minimise flicker, the rest will be overdrawn. */
fill(BLUE, x+45, 0, 5, gap);
fill(BLUE, x+45, gap+90, 5, 140-gap);
}
void clearFlappy(int x, int y)
void clear_flappy(int x, int y)
{
fill(BLUE, x, y, 34, 24);
}
void drawFlappy(int x, int y)
void draw_flappy(int x, int y)
{
// Upper & lower body
/* Upper & lower body */
fill(BLACK, x+2, y+8, 2, 10);
fill(BLACK, x+4, y+6, 2, 2);
fill(BLACK, x+6, y+4, 2, 2);
@@ -98,7 +104,7 @@ void drawFlappy(int x, int y)
fill(BLACK, x+4, y+18, 2, 2);
fill(BLACK, x+6, y+20, 4, 2);
// Body fill
/* Body fill */
fill(YELLOW, x+12, y+2, 6, 2);
fill(YELLOW, x+8, y+4, 8, 2);
fill(YELLOW, x+6, y+6, 10, 2);
@@ -110,7 +116,7 @@ void drawFlappy(int x, int y)
fill(YELLOW, x+6, y+18, 12, 2);
fill(YELLOW, x+10, y+20, 10, 2);
// Eye
/* Eye */
fill(BLACK, x+18, y+2, 2, 2);
fill(BLACK, x+16, y+4, 2, 6);
fill(BLACK, x+18, y+10, 2, 2);
@@ -120,7 +126,7 @@ void drawFlappy(int x, int y)
fill(WHITE, x+26, y+6, 2, 6);
fill(BLACK, x+24, y+6, 2, 4);
// Beak
/* Beak */
fill(BLACK, x+20, y+12, 12, 2);
fill(BLACK, x+18, y+14, 2, 2);
fill(RED, x+20, y+14, 12, 2);
@@ -134,8 +140,10 @@ void drawFlappy(int x, int y)
fill(BLACK, x+20, y+20, 10, 2);
}
// Wing down
void drawWing1(int x, int y)
/*
* Wing down.
*/
void draw_wing1(int x, int y)
{
fill(BLACK, x, y+14, 2, 6);
fill(BLACK, x+2, y+20, 8, 2);
@@ -147,8 +155,10 @@ void drawWing1(int x, int y)
fill(WHITE, x+10, y+14, 2, 2);
}
// Wing middle
void drawWing2(int x, int y)
/*
* Wing middle.
*/
void draw_wing2(int x, int y)
{
fill(BLACK, x+2, y+10, 10, 2);
fill(BLACK, x+2, y+16, 10, 2);
@@ -157,8 +167,10 @@ void drawWing2(int x, int y)
fill(WHITE, x+2, y+12, 10, 4);
}
// Wing up
void drawWing3(int x, int y)
/*
* Wing up.
*/
void draw_wing3(int x, int y)
{
fill(BLACK, x+2, y+6, 8, 2);
fill(BLACK, x, y+8, 2, 6);
@@ -180,13 +192,13 @@ time_t millis()
return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
}
void startGame()
void start_game()
{
fx = 50;
fy = 125;
fallRate = -1;
pillarPos = 320;
gapPos = 60;
fall_rate = -1;
pillar_pos = 320;
gap_pos = 60;
crashed = 0;
score = 0;
@@ -196,14 +208,11 @@ void startGame()
gpanel_text(&font_lucidasans15, WHITE, BLUE, 50, 180,
"(Press Space to start)");
//TODO: read high score value from file.
highScore = 0;
char score_line[80];
sprintf(score_line, "High Score: %u", high_score);
gpanel_text(&font_lucidasans28, GREEN, BLUE, 10, 60, score_line);
char scoreLine[80];
sprintf(scoreLine, "High Score: %u", highScore);
gpanel_text(&font_lucidasans28, GREEN, BLUE, 10, 60, scoreLine);
// Draw Ground
/* Draw ground. */
int tx, ty = 230;
for (tx = 0; tx <= 300; tx += 20) {
gpanel_fill_triangle(GREEN, tx, ty, tx+9, ty, tx, ty+9);
@@ -212,45 +221,45 @@ void startGame()
gpanel_fill_triangle(GREEN, tx+19, ty+9, tx+19, ty, tx+10, ty+9);
}
nextDrawLoopRunTime = millis() + DRAW_LOOP_INTERVAL;
next_draw_time = millis() + DRAW_LOOP_INTERVAL;
}
void drawLoop()
void draw_loop()
{
// clear moving items
clearPillar(pillarPos, gapPos);
clearFlappy(fx, fy);
/* Clear moving items. */
clear_pillar(pillar_pos, gap_pos);
clear_flappy(fx, fy);
// move items
/* Move items. */
if (running) {
fy += fallRate;
fallRate++;
fy += fall_rate;
fall_rate++;
pillarPos -= 5;
if (pillarPos == 0) {
pillar_pos -= 5;
if (pillar_pos == 0) {
score++;
}
else if (pillarPos < -50) {
pillarPos = 320;
gapPos = 20 + random() % 100;
else if (pillar_pos < -50) {
pillar_pos = 320;
gap_pos = 20 + random() % 100;
}
}
// draw moving items & animate
drawPillar(pillarPos, gapPos);
drawFlappy(fx, fy);
/* Draw moving items & animate. */
draw_pillar(pillar_pos, gap_pos);
draw_flappy(fx, fy);
switch (wing) {
case 0:
case 1:
drawWing1(fx, fy);
draw_wing1(fx, fy);
break;
case 2:
case 3:
drawWing2(fx, fy);
draw_wing2(fx, fy);
break;
case 4:
case 5:
drawWing3(fx, fy);
draw_wing3(fx, fy);
break;
}
wing++;
@@ -258,35 +267,77 @@ void drawLoop()
wing = 0;
}
void checkCollision()
/*
* Write high score value to file.
*/
void save_score()
{
// Collision with ground
int fd, nbytes;
char line[80];
fd = open(SCORE_FILENAME, O_WRONLY | O_CREAT, 0644);
if (fd < 0) {
perror(SCORE_FILENAME);
return;
}
sprintf(line, "%u\n", high_score);
nbytes = strlen(line);
if (write(fd, line, nbytes) != nbytes)
perror(SCORE_FILENAME);
close(fd);
}
/*
* Read high score value from file.
*/
void load_score()
{
int fd, nbytes;
char line[80];
fd = open(SCORE_FILENAME, O_RDONLY);
if (fd < 0) {
/* No high score file yet. */
return;
}
nbytes = read(fd, line, sizeof(line));
if (nbytes <= 0) {
if (nbytes < 0)
perror(SCORE_FILENAME);
return;
}
close(fd);
high_score = strtol(line, 0, 0);
}
void check_collision()
{
/* Collision with ground. */
if (fy > 206)
crashed = 1;
// Collision with pillar
if (fx + 34 > pillarPos && fx < pillarPos + 50)
if (fy < gapPos || fy + 24 > gapPos + 90)
/* Collision with pillar. */
if (fx + 34 > pillar_pos && fx < pillar_pos + 50)
if (fy < gap_pos || fy + 24 > gap_pos + 90)
crashed = 1;
if (crashed) {
gpanel_text(&font_lucidasans28, RED, BLUE, 50, 50, "Game Over!");
char scoreLine[80];
sprintf(scoreLine, "Score: %u", score);
gpanel_text(&font_lucidasans28, RED, BLUE, 50, 100, scoreLine);
char score_line[80];
sprintf(score_line, "Score: %u", score);
gpanel_text(&font_lucidasans28, RED, BLUE, 50, 100, score_line);
if (score > highScore) {
highScore = score;
if (score > high_score) {
high_score = score;
gpanel_text(&font_lucidasans28, RED, BLUE, 50, 150, "NEW HIGH!");
//TODO: Write high score value to file.
save_score();
}
// stop animation
/* Stop animation. */
running = 0;
// delay to stop any last minute clicks from restarting immediately
/* Delay to stop any last minute clicks from restarting immediately. */
sleep(1);
}
}
@@ -314,7 +365,7 @@ int get_input()
ioctl(0, TIOCGETP, &origtty);
newtty = origtty;
newtty.sg_flags &= ~(ECHO|CRMOD|XTABS);
newtty.sg_flags &= ~(ECHO|XTABS);
newtty.sg_flags |= CBREAK;
ioctl(0, TIOCSETP, &newtty);
}
@@ -334,45 +385,46 @@ int main()
char *devname = "/dev/tft0";
int xsize = 320, ysize = 240;
signal(SIGINT, quit);
if (gpanel_open(devname) < 0) {
printf("Cannot open %s\n", devname);
exit(-1);
}
gpanel_clear(BLUE, &xsize, &ysize);
startGame();
signal(SIGINT, quit);
load_score();
start_game();
for (;;) {
if (millis() > nextDrawLoopRunTime && !crashed) {
drawLoop();
checkCollision();
nextDrawLoopRunTime += DRAW_LOOP_INTERVAL;
if (millis() > next_draw_time && !crashed) {
draw_loop();
check_collision();
next_draw_time += DRAW_LOOP_INTERVAL;
}
usleep(10000);
// Get user input.
/* Get user input. */
int user_input = get_input();
// Process "user input"
if (user_input > 0 && !scrPress) {
/* Process "user input". */
if (user_input > 0 && !scr_press) {
if (crashed) {
// restart game
startGame();
/* Restart game. */
start_game();
}
else if (!running) {
// clear text & start scrolling
/* Clear text & start scrolling. */
gpanel_fill(BLUE, 0, 0, 320-1, 100);
gpanel_fill(BLUE, 0, 180, 320-1, 205);
running = 1;
} else {
// fly up
fallRate = -8;
scrPress = 1;
/* Fly up. */
fall_rate = -8;
scr_press = 1;
}
} else if (user_input == 0 && scrPress) {
// Attempt to throttle presses
scrPress = 0;
} else if (user_input == 0 && scr_press) {
/* Attempt to throttle presses. */
scr_press = 0;
}
}
}