From df576a3048498aad5aee566ec886a2a375c5a06c Mon Sep 17 00:00:00 2001 From: Lephenixnoir Date: Sat, 21 Aug 2021 14:49:01 +0200 Subject: [PATCH] add player rotation and collisions --- CMakeLists.txt | 2 +- src/duet.h | 20 ++++++++++++++-- src/main.c | 62 ++++++++++++++++++++++++++++++++++++++++---------- src/physics.c | 54 +++++++++++++++++++++++++++++++++++++++++++ src/render.c | 12 ++++++++++ 5 files changed, 135 insertions(+), 15 deletions(-) create mode 100644 src/physics.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 379033a..bca6ad8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,7 @@ find_package(Gint 2.1 REQUIRED) set(SOURCES src/main.c src/render.c - # ... + src/physics.c ) set(ASSETS assets-cg/example.png diff --git a/src/duet.h b/src/duet.h index 24cd51b..9ca207b 100644 --- a/src/duet.h +++ b/src/duet.h @@ -55,6 +55,10 @@ typedef struct { // Game //--- +#define PLAYER_X 55 +#define PLAYER_R 35 +#define PLAYER_SIZE 6 + typedef struct { float w, h; /* px */ float x, y; /* px */ @@ -65,7 +69,7 @@ typedef struct { #define RECT_TABLE_SIZE 20 -struct game { +typedef struct game { int dead; float time; level_t *level; @@ -73,7 +77,7 @@ struct game { rect_t table[RECT_TABLE_SIZE]; int cursor; float player_rota; -}; +} game_t; //--- // Rendering @@ -84,3 +88,15 @@ void dcircle(int x, int y, int r, int color, bool fill); void dtriangle(int x1, int y1, int x2, int y2, int x3, int y3, int color); void drectoid(rect_t const *r, int color); + +void render_player(float angle); + +//--- +// Physics +//--- + +void player_position(float angle, + float *x1, float *y1, float *x2, float *y2); + +bool player_collision(game_t const *game); +bool rect_circle_collide(rect_t const *r, int cx, int cy, int cr); diff --git a/src/main.c b/src/main.c index 2deb497..c9e3401 100644 --- a/src/main.c +++ b/src/main.c @@ -35,45 +35,83 @@ level_t level0 = { int main(void) { - volatile int need_frame; - struct game game; + volatile int need_frame = 1; + + game_t game; float dt = 0; int timer; __printf_enable_fp(); - - memset(&game, 0x00, sizeof(struct game)); + memset(&game, 0x00, sizeof game); game.level = &level0; + /* Temporary level */ + game.table[0] = (rect_t){ + .w=80, .h=20, .x=440, .y=50, .vx=-100, .vy=0, .r=0, .vr=0.5 + }; + game.cursor = 1; + timer = timer_configure(TIMER_ANY, 33000, GINT_CALL_SET(&need_frame)); timer_start(timer); + while (1) { + /* Time management */ + + while (need_frame == 0) sleep(); + need_frame = 0; + dt = (1.0 / 30) * level0.tempo; game.time += 1.0 / 30; + /* Input analysis */ + + bool rotate_left=false, rotate_right=false; + key_event_t e; while ((e = pollevent()).type != KEYEV_NONE) { if (e.type == KEYEV_DOWN && e.key == KEY_MENU) gint_osmenu(); } if (keydown(KEY_7)) { - game.player_rota += dt; + rotate_left = true; } if (keydown(KEY_0)) { - game.player_rota -= dt; + rotate_right = true; } - //TODO: physix + /* Level generation */ + /* TODO */ - dclear(C_BLACK); + /* Physics */ + +// if(player_collision(&game)) +// break; + + for(int i = 0; i < game.cursor; i++) { + rect_t *r = &game.table[i]; + r->x += r->vx * dt; + r->y += r->vy * dt; + r->r += r->vr * dt; + } + + if(rotate_left) + game.player_rota += M_PI * dt; + if(rotate_right) + game.player_rota -= M_PI * dt; + + /* Rendering */ + + dclear(player_collision(&game) ? C_RED : C_BLACK); dprint(0, 0, C_WHITE, "game time: %.2fs", game.time); dprint(0, 11, C_WHITE, "player rota: %.2f rad", game.player_rota); - dupdate(); - while (need_frame == 0) - sleep(); - need_frame = 0; + for(int i = 0; i < game.cursor; i++) + drectoid(&game.table[i], C_WHITE); + render_player(game.player_rota); + dupdate(); } + + timer_stop(timer); return (1); } diff --git a/src/physics.c b/src/physics.c new file mode 100644 index 0000000..4614e09 --- /dev/null +++ b/src/physics.c @@ -0,0 +1,54 @@ +#include "duet.h" + +void player_position(float angle, + float *x1, float *y1, float *x2, float *y2) +{ + int x=PLAYER_X, y=DHEIGHT/2; + + float sin, cos; + sincosf(angle, &sin, &cos); + + if(x1) *x1 = x + sin * PLAYER_R; + if(y1) *y1 = y + cos * PLAYER_R; + + if(x2) *x2 = x - sin * PLAYER_R; + if(y2) *y2 = y - cos * PLAYER_R; +} + +bool player_collision(game_t const *game) +{ + float x1, y1, x2, y2; + player_position(game->player_rota, &x1, &y1, &x2, &y2); + + for(int i = 0; i < game->cursor; i++) { + if(rect_circle_collide(&game->table[i], x1, y1, PLAYER_SIZE)) + return true; + if(rect_circle_collide(&game->table[i], x2, y2, PLAYER_SIZE)) + return true; + } + + return false; +} + +bool rect_circle_collide(rect_t const *r, int cx0, int cy0, int cr) +{ + /* Translate so that rectangle center is (0,0) */ + cx0 -= r->x; + cy0 -= r->y; + + /* Rotate so that rectangle is flat */ + float sin, cos; + sincosf(-r->r, &sin, &cos); + float cx = cx0 * cos + cy0 * sin; + float cy = -cx0 * sin + cy0 * cos; + + /* Determine point of rectangle closest to center of circle */ + float clx=cx, cly=cy; + if(clx < -r->w/2) clx = -r->w/2; + if(clx > r->w/2) clx = r->w/2; + if(cly < -r->h/2) cly = r->h/2; + if(cly > r->h/2) cly = r->h/2; + + /* Determine whether that point is in the circle */ + return (clx - cx) * (clx - cx) + (cly - cy) * (cly - cy) <= cr * cr; +} diff --git a/src/render.c b/src/render.c index b36931a..0383527 100644 --- a/src/render.c +++ b/src/render.c @@ -97,3 +97,15 @@ void drectoid(rect_t const *r, int color) dtriangle(x[0], y[0], x[1], y[1], x[2], y[2], color); dtriangle(x[2], y[2], x[3], y[3], x[0], y[0], color); } + +void render_player(float angle) +{ + int x=PLAYER_X, y=DHEIGHT/2; + dcircle(x, y, PLAYER_R, C_WHITE, false); + + float x1, y1, x2, y2; + player_position(angle, &x1, &y1, &x2, &y2); + + dcircle(x1, y1, PLAYER_SIZE, C_RGB(0, 16, 26), true); + dcircle(x2, y2, PLAYER_SIZE, C_RGB(31, 6, 0), true); +}