diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a358e49 --- /dev/null +++ b/Makefile @@ -0,0 +1,10 @@ +flappy: main.o game.o bird.o pipe.o + gcc -o flappy main.o game.o bird.o pipe.o -lcurses +main.o: main.c game.h config.h + gcc -c main.c +game.o: game.c game.h bird.h pipe.h config.h + gcc -c game.c +bird.o: bird.c bird.h config.h + gcc -c bird.c +pipe.o: pipe.c pipe.h config.h + gcc -c pipe.c \ No newline at end of file diff --git a/bird.c b/bird.c new file mode 100644 index 0000000..d48621c --- /dev/null +++ b/bird.c @@ -0,0 +1,18 @@ +#include "bird.h" + +bird* bird_create(){ + /* Allocate memory */ + bird* b = malloc(sizeof(bird)); + + /* Set values */ + b->pos_x = CAM_OFFSET_X; + b->pos_y = HEIGHT/2; + b->vel_x = BIRD_VEL_X; + b->vel_y = 0; + + return b; +} + +void bird_destroy(bird* b){ + free(b); +} \ No newline at end of file diff --git a/bird.h b/bird.h new file mode 100644 index 0000000..b9d2976 --- /dev/null +++ b/bird.h @@ -0,0 +1,17 @@ +#ifndef _H_BIRD +#define _H_BIRD + +#include +#include "config.h" + +typedef struct{ + float pos_x; + float pos_y; + float vel_x; + float vel_y; +} bird; + +bird* bird_create(); +void bird_destroy(bird* b); + +#endif \ No newline at end of file diff --git a/config.h b/config.h new file mode 100644 index 0000000..7d4a9e7 --- /dev/null +++ b/config.h @@ -0,0 +1,19 @@ +#ifndef _H_CONFIG +#define _H_CONFIG + +#define KEY_QUIT 'q' +#define KEY_JUMP ' ' + +#define FPS 10 +#define WIDTH 60 +#define HEIGHT 20 +#define CAM_OFFSET_X 10 + +#define BIRD_VEL_X 10.0F +#define BIRD_VEL_Y_JUMP 13.5F +#define BIRD_ACC_Y -30.0F + +#define PIPE_DISTANCE 16 +#define PIPE_HEIGHT 3 + +#endif \ No newline at end of file diff --git a/flappy b/flappy new file mode 100755 index 0000000..5397585 Binary files /dev/null and b/flappy differ diff --git a/game.c b/game.c new file mode 100644 index 0000000..d7bac49 --- /dev/null +++ b/game.c @@ -0,0 +1,126 @@ +#include "game.h" + +game* game_create(){ + /* Allocate memory */ + game* g = malloc(sizeof(game)); + + /* Set vars */ + g->bird = bird_create(); + g->num_pipes = WIDTH/PIPE_DISTANCE + 1; + g->pipes = malloc(sizeof(pipe*)*g->num_pipes); + for(int i=0; inum_pipes; i++){ + g->pipes[i] = pipe_create(); + } + g->score = 0; + g->highscore = 0; + + /* Reset level */ + game_reset_level(g); + + return g; +} + +void game_reset_level(game* g){ + /* Reset bird */ + bird_destroy(g->bird); + g->bird = bird_create(); + + /* Reset pipes */ + for(int i=0; inum_pipes; i++){ + g->pipes[i]->pos_x = WIDTH + PIPE_DISTANCE*i; + g->pipes[i]->pos_y = rand()%(HEIGHT-PIPE_HEIGHT-2)+1; + g->pipes[i]->height = PIPE_HEIGHT; + } + + /* Reset other vars */ + g->score = 0; +} + +void game_destroy(game* g){ + /* Free memory */ + bird_destroy(g->bird); + for(int i=0; inum_pipes; i++){ + pipe_destroy(g->pipes[i]); + } + free(g->pipes); + free(g); +} + +void game_key_pressed(game* g, char key){ + if(key == KEY_JUMP){ + g->bird->vel_y = BIRD_VEL_Y_JUMP; + } +} + +int game_update(game* g, float dt){ + /* Update bird position */ + g->bird->vel_y += BIRD_ACC_Y * dt; + g->bird->pos_x += g->bird->vel_x * dt; + g->bird->pos_y += g->bird->vel_y * dt; + + /* Check for collisions */ + int bird_x = g->bird->pos_x; + for(int i=0; inum_pipes; i++){ + if(bird_x == g->pipes[i]->pos_x){ + int bird_y = g->bird->pos_y; + if(bird_y < g->pipes[i]->pos_y || bird_y >= g->pipes[i]->pos_y + g->pipes[i]->height){ + /* Collision */ + return STATE_COLLISION; + } + } + } + if(g->bird->pos_y < 0){ + return STATE_COLLISION; + } + + /* Move pipes */ + for(int i=0; inum_pipes; i++){ + /* Check if off screen */ + if(g->pipes[i]->pos_x < g->bird->pos_x-CAM_OFFSET_X){ + /* Move */ + g->pipes[i]->pos_x += g->num_pipes*PIPE_DISTANCE; + g->pipes[i]->pos_y = rand()%(HEIGHT-PIPE_HEIGHT-2)+1; + + /* Adjust score */ + g->score++; + } + } + + return STATE_OKAY; +} + +void game_render(game* g){ + /* Clear screen */ + clear(); + + /* Init vars */ + int delta_x = g->bird->pos_x - CAM_OFFSET_X; + + /* Draw ground */ + move(HEIGHT, 0); + for(int x=0; xpipes[i]->pos_y+g->pipes[i]->height+1; ybird->pos_y, CAM_OFFSET_X, 'v'); + + /* Draw score */ + char text[50]; + sprintf(text, "Score: %d\tBest: %d", g->score, g->highscore); + mvaddstr(HEIGHT+1, 1, text); +} \ No newline at end of file diff --git a/game.h b/game.h new file mode 100644 index 0000000..ae078f8 --- /dev/null +++ b/game.h @@ -0,0 +1,30 @@ +#ifndef _H_GAME +#define _H_GAME + +#include +#include +#include "bird.h" +#include "pipe.h" +#include "config.h" + +#define STATE_OKAY 0 +#define STATE_COLLISION 1 + +typedef struct{ + bird* bird; + pipe** pipes; + int num_pipes; + int score; + int highscore; +} game; + +game* game_create(); +void game_reset_level(game* g); +void game_destroy(game* g); + +void game_key_pressed(game* g, char key); +int game_update(game* g, float dt); +void game_render(game* g); + + +#endif \ No newline at end of file diff --git a/main.c b/main.c new file mode 100644 index 0000000..1a2447c --- /dev/null +++ b/main.c @@ -0,0 +1,77 @@ +#include +#include +#include +#include +#include "game.h" +#include "config.h" + +void msleep(int msec){ + struct timespec ts; + ts.tv_sec = msec/1000; + ts.tv_nsec = (msec%1000) * 1000000; + nanosleep(&ts, &ts); +} + +int main(int argc, char** argv){ + + /* Init curses */ + WINDOW* win; + win = initscr(); + noecho(); + keypad(win, TRUE); + nodelay(win, TRUE); + curs_set(FALSE); + + /* Init game */ + srand(time(NULL)); + game* g = game_create(); + + /* Game Loop */ + char c; + while(1){ + /* Get input */ + do{ + c = getch(); + if(c == KEY_QUIT) break; + if(c != ERR) game_key_pressed(g, c); + }while(c != ERR); + if(c == KEY_QUIT) break; + + /* Update */ + int state = game_update(g, 1.0F/(float)FPS); + + /* Render */ + game_render(g); + refresh(); + + /* Exit if collision */ + if(state == STATE_COLLISION){ + /* Update score */ + char is_best_score = 0; + if(g->score > g->highscore){ + g->highscore = g->score; + is_best_score = 1; + } + + /* Draw message */ + move(HEIGHT+2, 1); + addstr((is_best_score ? "New Highscore!" : "Game Over!")); + refresh(); + + /* Delay and restart */ + msleep(1000); + game_reset_level(g); + } + + /* Delay */ + msleep(1000/FPS); + } + + /* Cleanup */ + game_destroy(g); + delwin(win); + endwin(); + refresh(); + + return 0; +} \ No newline at end of file diff --git a/pipe.c b/pipe.c new file mode 100644 index 0000000..c5b4105 --- /dev/null +++ b/pipe.c @@ -0,0 +1,17 @@ +#include "pipe.h" + +pipe* pipe_create(){ + /* Allocate memory */ + pipe* p = malloc(sizeof(pipe)); + + /* Set values */ + p->pos_x = 0; + p->pos_y = 0; + p->height = PIPE_HEIGHT; + + return p; +} + +void pipe_destroy(pipe* p){ + free(p); +} \ No newline at end of file diff --git a/pipe.h b/pipe.h new file mode 100644 index 0000000..e88ab6a --- /dev/null +++ b/pipe.h @@ -0,0 +1,16 @@ +#ifndef _H_PIPE +#define _H_PIPE + +#include +#include "config.h" + +typedef struct { + int pos_x; + int pos_y; + int height; +} pipe; + +pipe* pipe_create(); +void pipe_destroy(pipe* p); + +#endif \ No newline at end of file diff --git a/project.code-workspace b/project.code-workspace new file mode 100644 index 0000000..362d7c2 --- /dev/null +++ b/project.code-workspace @@ -0,0 +1,7 @@ +{ + "folders": [ + { + "path": "." + } + ] +} \ No newline at end of file