From d9339443221165fd6200c5f7aac6cf7a8e4811ac Mon Sep 17 00:00:00 2001 From: Lephenixnoir Date: Sun, 16 Jan 2022 11:29:46 +0100 Subject: [PATCH] time parameterization + forced rotation direction --- TODO | 4 ++ assets-cg/levels.png | Bin 401 -> 6888 bytes src/duet.h | 5 ++- src/main.c | 90 ++++++++++++++++++++++++++++++------------- src/physics.c | 13 +++++++ 5 files changed, 83 insertions(+), 29 deletions(-) create mode 100644 TODO diff --git a/TODO b/TODO new file mode 100644 index 0000000..d145526 --- /dev/null +++ b/TODO @@ -0,0 +1,4 @@ +* Tighter than the original? +* Count number of turns, with optimal +* Add performance counters +* Check if level tempo is accounted for diff --git a/assets-cg/levels.png b/assets-cg/levels.png index 0144b47f3865463fd9fa289cfa0d75deab988eb3..a97e0e2c1e3a7f35348d4bbbde89e836e82c862a 100644 GIT binary patch literal 6888 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 J@g9$({{e(xFIE5m delta 348 zcmV-i0i*utHIV}$iBL{Q4GJ0x0000DNk~Le0000V0003O2nGNE09A^g;FE9}9t!0M z6&4H{l$NDQlb9JOe+x-OK~#9!?b<<(fJQ81pd580Q56^RQ$=ql4KzPFtWrBX0{ zGSdVAcQGIRu-3Xn2b5BFXFPoV0000&Q7BqC3kLuIzB*&!ES!b2Z~y?lM)8kot;?r{ zeP$0#yVN2Bk1ny$@W{ZX;aLMO4SzQ@GO+pfnl*I%ci#P+e-E+k!(8V*_9Ok?4ghF1 zt)|tqnpV?lS`7fuYFbUJX*I2;)wJ56{9_gXLQyCRMWHAZg`!YIC}QCNRH{lXO4V~+re8O9Cdvx(sdz! u=Ydd{bKYg!B3s|l>+dx$;kWN_!2PXpo|+|a*3EnX0000 //--- -// Level strucutres +// Level structures //--- typedef enum { @@ -149,7 +149,8 @@ extern level_t level5, level6, level7, level8; extern level_t level9, level10, level11, level12; extern level_t level13, level14, level15, level16; extern level_t level17, level18, level19, level20; -extern level_t level21, level22; +extern level_t level21, level22, level23, level24; +extern level_t level25, level26, level27, level28; extern episode_t episodes[]; extern int episode_count; diff --git a/src/main.c b/src/main.c index debbc37..a5ec4c1 100644 --- a/src/main.c +++ b/src/main.c @@ -54,8 +54,15 @@ episode_t episodes[] = { &level22, }, }, + { + .name = "guilt", + .level_count = 1, + .levels = (level_t *[]) { + &level22, // TODO + }, + }, }; -int episode_count = 4; +int episode_count = sizeof(episodes) / sizeof(episodes[0]); void load_level(game_t *game, level_t const *lv) { @@ -80,6 +87,20 @@ int strcount(char const *str, int c) return count; } +/* Round player rotation to closest multiple of M_PI */ +float rpr(float rota) +{ + if(fabs(rota) <= M_PI_2) + return 0; + return (rota < 0) ? -M_PI : M_PI; +} + +/* Forced player rotation to go back to an even position */ +float fpr(float rota, float duration) +{ + return (rpr(rota) - rota) / duration; +} + void game_loop(int current_episode, int current_level) { game_t game; @@ -89,19 +110,34 @@ void game_loop(int current_episode, int current_level) state_t state = State_Playing; - if(current_level == 0) { - state = State_EpisodeTransition; - game.time_episode_transition = 0; - game.time = -14.0; - } - /* Direction of time (with a factor regulating game speed) */ float const time_direction_forward = 2.7; float const time_direction_rewind = -25; + /* Level time to start (negative to leave time before blocks arrive) */ + float const LEVEL_START = -14.0; + /* Level time until which message is shown */ + float const MESSAGE_END = -5.0; + /* Duration of death pause (seconds) */ + float const DEATH_PAUSE_DURATION = 0.7; + /* Level time to restarting playing at after rewind */ + float const REWIND_END = -5.0; + /* Duration of level transitions (seconds) */ + float const TRANSITION_DURATION = 1.0; + /* Duration of episode transitions (seconds) + Warning: overlaps with pre-level, will lock player if too long x_x */ + float const EPISODE_TRANSITION_DURATION = 3.0; volatile int need_frame = 1; int timer = timer_configure(TIMER_ANY, 33000, GINT_CALL_SET(&need_frame)); if(timer >= 0) timer_start(timer); + /* Frame duration in real time */ + float const FRAME_DURATION = 1.0 / 30; + + if(current_level == 0) { + state = State_EpisodeTransition; + game.time_episode_transition = 0; + game.time = LEVEL_START; + } while (1) { level_t const *lv = game.level; @@ -116,38 +152,37 @@ void game_loop(int current_episode, int current_level) time_direction = time_direction_rewind; if(state == State_Dead) { - game.time_dead += (1.0 / 30); - if(game.time_dead >= 0.7) { + game.time_dead += FRAME_DURATION; + if(game.time_dead >= DEATH_PAUSE_DURATION) { game.time_dead = 0; - game.forced_player_rota = game.player_rota / (game.time + 5.0); + game.forced_player_rota = fpr(game.player_rota, + REWIND_END - game.time); state = State_Rewind; } - continue; + continue; /* Pause effect */ } if(state == State_Transition) { time_direction = 1.0; - game.time_transition += (1.0 / 30); - if(game.time_transition >= 1.0) { + game.time_transition += FRAME_DURATION; + if(game.time_transition >= TRANSITION_DURATION) { game.time_transition = 0; - game.player_rota = 0; game.forced_player_rota = 0; state = State_Playing; } } if(state == State_EpisodeTransition) { time_direction = 1.0; - game.time_episode_transition += (1.0 / 30); - if(game.time_episode_transition >= 1.0) { - game.player_rota = 0; + game.time_episode_transition += FRAME_DURATION; + if(game.time_episode_transition >= TRANSITION_DURATION) { game.forced_player_rota = 0; } - if(game.time_episode_transition >= 3.0) { + if(game.time_episode_transition >= EPISODE_TRANSITION_DURATION) { game.time_episode_transition = 0; state = State_Playing; } } - float dt = (1.0 / 30) * time_direction; + float dt = FRAME_DURATION * time_direction; game.time += dt; /* Input analysis */ @@ -193,23 +228,24 @@ void game_loop(int current_episode, int current_level) if(changed_episode) { state = State_EpisodeTransition; game.time_episode_transition = 0; - game.forced_player_rota = -game.player_rota / 1.0; - game.time = -13.0; + game.forced_player_rota = fpr(game.player_rota, + TRANSITION_DURATION); + game.time = LEVEL_START; continue; } else { state = State_Transition; game.time_transition = 0; - game.forced_player_rota = -game.player_rota / 1.0; + game.forced_player_rota = fpr(game.player_rota, + TRANSITION_DURATION); continue; } } // End of rewind - if(state == State_Rewind && game.time <= -5.0) { - game.time = -5.0; - game.player_rota = 0.0; - game.forced_player_rota = 0.0; + if(state == State_Rewind && game.time <= REWIND_END) { + game.time = REWIND_END; + game.forced_player_rota = 0; state = State_Playing; continue; } @@ -255,7 +291,7 @@ void game_loop(int current_episode, int current_level) dma_memcpy(gint_vram + 396*(40*j), gint_vram, 396*2*lines); } - if(state == State_Playing && game.time < -4.0 && lv->message) { + if(state == State_Playing && game.time < MESSAGE_END && lv->message) { int x = DWIDTH/2 + 8 * (strcount(lv->message, '\n') + 1); /* Split at newlines */ diff --git a/src/physics.c b/src/physics.c index 12a5338..58d91db 100644 --- a/src/physics.c +++ b/src/physics.c @@ -136,6 +136,9 @@ void rect_physics(rect_t *r, rectmeta_t const *meta, float absolute_time) float speeding_period = fminf(2.0, fmaxf(0.0, time + 6.0)); r->x -= RECT_SPEED * speeding_period; } + else if(meta->action == Action_FadeOut) { + // TODO + } else if(meta->action == Action_OuterRotateLeft) { float vr = 0.7; /* rad/tempo */ r->r = time * vr; @@ -144,4 +147,14 @@ void rect_physics(rect_t *r, rectmeta_t const *meta, float absolute_time) float vr = 0.7; /* rad/tempo */ r->r = -time * vr; } + else if(meta->action == Action_Slide) { + // TODO + } + else if(meta->action == Action_Speed2) { + /* Double speed permanently */ + // TODO + } + else if(meta->action == Action_Speed3) { + // TODO + } }