From 7072fe447d09bc01e81795a283dd73587a7a8145 Mon Sep 17 00:00:00 2001 From: Andrei Alexeyev Date: Sat, 16 May 2020 23:42:22 +0300 Subject: [PATCH] Revamp screen shake system (#225) --- src/boss.c | 25 ++++++++-------------- src/global.h | 3 --- src/plrmodes/marisa_a.c | 6 ++---- src/plrmodes/marisa_b.c | 4 +--- src/plrmodes/reimu_a.c | 4 +--- src/plrmodes/reimu_b.c | 4 ++-- src/stage.c | 40 +++++++++++++++++++++++----------- src/stage.h | 3 +++ src/stagedraw.c | 42 ++++++++++++++++++++---------------- src/stages/stage5_events.c | 8 ++----- src/stages/stage6_events.c | 44 ++++++++++++++++---------------------- 11 files changed, 88 insertions(+), 95 deletions(-) diff --git a/src/boss.c b/src/boss.c index 341193e4..1d8c9e0a 100644 --- a/src/boss.c +++ b/src/boss.c @@ -1050,20 +1050,18 @@ void process_boss(Boss **pboss) { float p = (boss->current->endtime - global.frames)/(float)ATTACK_END_DELAY_EXTRA; float a = fmax((base + ampl * s) * p * 0.5, 5 * pow(1 - p, 3)); if(a < 2) { - global.shake_view = 3 * a; + stage_shake_view(3 * a); boss_rule_extra(boss, a); if(a > 1) { boss_rule_extra(boss, a * 0.5); if(a > 1.3) { - global.shake_view = 5 * a; + stage_shake_view(5 * a); if(a > 1.7) - global.shake_view += 2 * a; + stage_shake_view(2 * a); boss_rule_extra(boss, 0); boss_rule_extra(boss, 0.1); } } - } else { - global.shake_view_fade = 0.15; } } else if(time < 0) { boss_rule_extra(boss, 1+time/(float)ATTACK_START_DELAY_EXTRA); @@ -1074,12 +1072,10 @@ void process_boss(Boss **pboss) { boss_rule_extra(boss, fmax(1-time/300.0, base + ampl * s) * q); if(o) { boss_rule_extra(boss, fmax(1-time/300.0, base + ampl * s) - o); - if(!global.shake_view) { - global.shake_view = 5; - global.shake_view_fade = 0.9; - } else if(o > -0.05) { - global.shake_view = 10; - global.shake_view_fade = 0.5; + + stage_shake_view(5); + if(o > -0.05) { + stage_shake_view(10); } } } @@ -1131,11 +1127,7 @@ void process_boss(Boss **pboss) { ); if(!extra) { - if(t == 1) { - global.shake_view_fade = 0.2; - } else { - global.shake_view = 5 * (t + t*t + t*t*t); - } + stage_shake_view(5 * (t + t*t + t*t*t)); } if(t == 1) { @@ -1277,6 +1269,7 @@ void boss_death(Boss **boss) { if(!fleed) { stage_clear_hazards(CLEAR_HAZARDS_ALL | CLEAR_HAZARDS_FORCE); + stage_shake_view(100); PARTICLE( .pos = (*boss)->pos, diff --git a/src/global.h b/src/global.h index c842de39..a4c7c7ee 100644 --- a/src/global.h +++ b/src/global.h @@ -126,9 +126,6 @@ typedef struct { ReplayMode replaymode; ReplayStage *replay_stage; - float shake_view; - float shake_view_fade; - uint voltage_threshold; RandomState rand_game; diff --git a/src/plrmodes/marisa_a.c b/src/plrmodes/marisa_a.c index f76658c7..cf6a6350 100644 --- a/src/plrmodes/marisa_a.c +++ b/src/plrmodes/marisa_a.c @@ -533,11 +533,11 @@ TASK(marisa_laser_masterspark, { MarisaAController *ctrl; }) { marisa_laser_masterspark_damage(ms); if(bomb_progress >= 3.0/4.0) { - global.shake_view = 8 * (1 - bomb_progress * 4 + 3); + stage_shake_view(8 * (1 - bomb_progress * 4 + 3)); goto skip_particles; } - global.shake_view = 8; + stage_shake_view(8); uint pflags = PFLAG_NOREFLECT | PFLAG_MANUALANGLE; @@ -581,8 +581,6 @@ skip_particles: YIELD; } while(player_is_bomb_active(plr)); - global.shake_view = 0; - while(ms->alpha > 0) { approach_p(&ms->alpha, 0, 0.2); YIELD; diff --git a/src/plrmodes/marisa_b.c b/src/plrmodes/marisa_b.c index 37909c14..e26750f6 100644 --- a/src/plrmodes/marisa_b.c +++ b/src/plrmodes/marisa_b.c @@ -436,7 +436,7 @@ TASK(marisa_star_bomb_controller, { MarisaBController *ctrl; }) { } do { - global.shake_view = fmax(8, global.shake_view); + stage_shake_view(8); player_placeholder_bomb_logic(plr); float tb = player_get_bomb_progress(plr); @@ -457,8 +457,6 @@ TASK(marisa_star_bomb_controller, { MarisaBController *ctrl; }) { ++beams->time; YIELD; } while(player_is_bomb_active(plr)); - - global.shake_view = 0; } TASK(marisa_star_bomb_handler, { MarisaBController *ctrl; }) { diff --git a/src/plrmodes/reimu_a.c b/src/plrmodes/reimu_a.c index d6d21a1e..a5ff98ed 100644 --- a/src/plrmodes/reimu_a.c +++ b/src/plrmodes/reimu_a.c @@ -217,8 +217,7 @@ TASK(reimu_spirit_bomb_orb_impact, { BoxedProjectile orb; }) { play_sound("boom"); play_sound("spellend"); - global.shake_view = 20; - global.shake_view_fade = 0.6; + stage_shake_view(200); real damage = 2000; real range = 300; @@ -429,7 +428,6 @@ TASK(reimu_spirit_bomb_handler, { ReimuAController *ctrl; }) { WAIT_EVENT_OR_DIE(&plr->events.bomb_used); INVOKE_SUBTASK(reimu_spirit_bomb_background, ctrl); - global.shake_view = 4; play_sound("bomb_reimu_a"); play_sound("bomb_marisa_b"); diff --git a/src/plrmodes/reimu_b.c b/src/plrmodes/reimu_b.c index ed24378a..2b8815a5 100644 --- a/src/plrmodes/reimu_b.c +++ b/src/plrmodes/reimu_b.c @@ -171,7 +171,7 @@ TASK(reimu_dream_bomb_barrage, { ReimuBController *ctrl; }) { ); } - global.shake_view += 6; + stage_shake_view(4); t += WAIT(BOMB_PROJECTILE_FIRE_DELAY); } while(player_is_bomb_active(plr)); } @@ -611,7 +611,7 @@ TASK(reimu_dream_controller_tick, { ReimuBController *ctrl; }) { for(;;) { if(player_is_bomb_active(plr)) { - global.shake_view_fade = fmax(global.shake_view_fade, 2); + stage_shake_view(1); approach_p(&ctrl->bomb_alpha, 1.0, 0.1); } else { approach_p(&ctrl->bomb_alpha, 0.0, 0.025); diff --git a/src/stage.c b/src/stage.c index 5320d4c4..e2bfb565 100644 --- a/src/stage.c +++ b/src/stage.c @@ -31,7 +31,6 @@ static void stage_start(StageInfo *stage) { global.timer = 0; global.frames = 0; global.gameover = 0; - global.shake_view = 0; global.voltage_threshold = 0; player_stage_pre_init(&global.plr); @@ -579,8 +578,11 @@ typedef struct StageFrameState { int transition_delay; int logic_calls; uint16_t last_replay_fps; + float view_shake; } StageFrameState; +static StageFrameState *_current_stage_state; // TODO remove this shitty hack + static void stage_update_fps(StageFrameState *fstate) { if(global.replaymode == REPLAY_RECORD) { uint16_t replay_fps = (uint16_t)rint(global.fps.logic.fps); @@ -638,17 +640,8 @@ static LogicFrameAction stage_logic_frame(void *arg) { global.plr.iddqd = true; } - if(global.shake_view > 30) { - global.shake_view = 30; - } - - if(global.shake_view_fade) { - global.shake_view -= global.shake_view_fade; - - if(global.shake_view <= 0) { - global.shake_view = global.shake_view_fade = 0; - } - } + fapproach_p(&fstate->view_shake, 0, 1); + fapproach_asymptotic_p(&fstate->view_shake, 0, 0.05, 1e-2); ((global.replaymode == REPLAY_PLAY) ? replay_input : stage_input)(); @@ -688,6 +681,7 @@ static LogicFrameAction stage_logic_frame(void *arg) { } if(global.gameover > 0) { + log_warn("RESTART"); return LFRAME_STOP; } @@ -822,6 +816,8 @@ void stage_enter(StageInfo *stage, CallChain next) { fstate->stage = stage; fstate->cc = next; + _current_stage_state = fstate; + #ifdef DEBUG _skip_to_dialog = env_get_int("TAISEI_SKIP_TO_DIALOG", 0); _skip_to_bookmark = env_get_string_nonempty("TAISEI_SKIP_TO_BOOKMARK", NULL); @@ -840,6 +836,7 @@ void stage_enter(StageInfo *stage, CallChain next) { void stage_end_loop(void* ctx) { StageFrameState *s = ctx; + assert(s == _current_stage_state); if(global.replaymode == REPLAY_RECORD) { replay_stage_event(global.replay_stage, global.frames, EV_OVER, 0); @@ -868,8 +865,12 @@ void stage_end_loop(void* ctx) { global.gameover = GAMEOVER_ABORT; } - run_call_chain(&s->cc, NULL); + _current_stage_state = NULL; + + CallChain cc = s->cc; free(s); + + run_call_chain(&cc, NULL); } void stage_unlock_bgm(const char *bgm) { @@ -877,3 +878,16 @@ void stage_unlock_bgm(const char *bgm) { progress_unlock_bgm(bgm); } } + +void stage_shake_view(float strength) { + assume(strength >= 0); + _current_stage_state->view_shake += strength; +} + +float stage_get_view_shake_strength(void) { + if(_current_stage_state) { + return _current_stage_state->view_shake; + } + + return 0; +} diff --git a/src/stage.h b/src/stage.h index 648c9752..aa8a716e 100644 --- a/src/stage.h +++ b/src/stage.h @@ -101,6 +101,9 @@ void stage_unlock_bgm(const char *bgm); void stage_begin_dialog(Dialog *d) attr_nonnull_all; +void stage_shake_view(float strength); +float stage_get_view_shake_strength(void); + #ifdef DEBUG void _stage_bookmark(const char *name); #define STAGE_BOOKMARK(name) _stage_bookmark(#name) diff --git a/src/stagedraw.c b/src/stagedraw.c index 4f5c4135..eccbd552 100644 --- a/src/stagedraw.c +++ b/src/stagedraw.c @@ -46,23 +46,22 @@ static struct { ShaderProgram *copy_depth; } shaders; - struct { - float alpha; - float target_alpha; - } clear_screen; - PostprocessShader *viewport_pp; FBPair fb_pairs[NUM_FBPAIRS]; FBPair powersurge_fbpair; FBPair *current_postprocess_fbpair; + ManagedFramebufferGroup *mfb_group; + StageDrawEvents events; + + struct { + float alpha; + float target_alpha; + } clear_screen; + bool framerate_graphs; bool objpool_stats; - ManagedFramebufferGroup *mfb_group; - - StageDrawEvents events; - #ifdef DEBUG Sprite dummy; #endif @@ -906,28 +905,33 @@ static void postprocess_prepare(Framebuffer *fb, ShaderProgram *s, void *arg) { } static inline void begin_viewport_shake(void) { - if(global.shake_view) { + float s = stage_get_view_shake_strength(); + + if(s > 0) { +// s = log1pf(s); + s = sqrtf(s); + r_mat_mv_push(); r_mat_mv_translate( - global.shake_view * sin(global.frames), - global.shake_view * sin(global.frames * 1.1 + 3), + s * sin(global.frames), + s * sin(global.frames * 1.1 + 3), 0 ); r_mat_mv_scale( - 1 + 2 * global.shake_view / VIEWPORT_W, - 1 + 2 * global.shake_view / VIEWPORT_H, + 1 + 2 * s / VIEWPORT_W, + 1 + 2 * s / VIEWPORT_H, 1 ); r_mat_mv_translate( - -global.shake_view, - -global.shake_view, + -s, + -s, 0 ); } } static inline void end_viewport_shake(void) { - if(global.shake_view) { + if(stage_get_view_shake_strength() > 0) { r_mat_mv_pop(); } } @@ -942,7 +946,7 @@ void stage_draw_begin_noshake(void) { assert(!shake_suppressed); shake_suppressed = 1; - if(global.shake_view) { + if(stage_get_view_shake_strength() > 0) { shake_suppressed = 2; r_mat_mv_push_identity(); } @@ -951,7 +955,7 @@ void stage_draw_begin_noshake(void) { void stage_draw_end_noshake(void) { assert(shake_suppressed); - if(global.shake_view) { + if(stage_get_view_shake_strength() > 0) { // make sure shake_view doesn't change in-between the begin/end calls; // that would've been *really* nasty to debug. assert(shake_suppressed == 2); diff --git a/src/stages/stage5_events.c b/src/stages/stage5_events.c index 5519a814..dc81ce3c 100644 --- a/src/stages/stage5_events.c +++ b/src/stages/stage5_events.c @@ -1094,8 +1094,7 @@ static int iku_extra_trigger_bullet(Projectile *p, int t) { .args = { dir, 10 }, ); } - global.shake_view += 5; - global.shake_view_fade = 0.2; + stage_shake_view(40); aniplayer_hard_switch(&global.boss->ani,"main_mirror",0); play_sound("boom"); return ACTION_DESTROY; @@ -1195,9 +1194,6 @@ static int iku_extra_slave(Enemy *e, int t) { Laser *l; int cnt = 6 + 2 * global.diff, i; - global.shake_view = 0; - global.shake_view_fade = 0.2; - e->args[2] = 1; for(o = global.enemies.first; o; o = o->next) { @@ -1217,7 +1213,7 @@ static int iku_extra_slave(Enemy *e, int t) { o->args[1] = 0; o->args[2] = 0; - global.shake_view += 1; + stage_shake_view(5); } for(l = global.lasers.first; l; l = l->next) { diff --git a/src/stages/stage6_events.c b/src/stages/stage6_events.c index acbed9f9..ad64cae2 100644 --- a/src/stages/stage6_events.c +++ b/src/stages/stage6_events.c @@ -925,7 +925,7 @@ static int scythe_explode(Enemy *e, int t) { if(t == 100) { petal_explosion(100, e->pos); - global.shake_view = 16; + stage_shake_view(16); play_sound("boom"); scythe_common(e, t); @@ -990,8 +990,14 @@ static void elly_paradigm_shift(Boss *b, int t) { elly_spawn_baryons(b->pos); } + /* if(t > 120) global.shake_view = fmax(0, 16-0.26*(t-120)); + */ + + AT(120) { + stage_shake_view(200); + } } static void set_baryon_rule(EnemyLogicRule r) { @@ -1160,8 +1166,7 @@ static int broglie_charge(Projectile *p, int t) { play_sound_ex("laser1", 10, true); play_sound("boom"); - global.shake_view = 5.0; - global.shake_view_fade = 0.25; + stage_shake_view(20); Color clr = p->color; clr.a = 0; @@ -1747,7 +1752,6 @@ void elly_lhc(Boss *b, int t) { set_baryon_rule(baryon_lhc); AT(EVENT_DEATH) { set_baryon_rule(baryon_reset); - global.shake_view_fade=1; } FROM_TO(260, 10000, 400) { @@ -1759,7 +1763,7 @@ void elly_lhc(Boss *b, int t) { int c = 30+10*global.diff; cmplx pos = VIEWPORT_W/2 + 100.0*I+400.0*I*((t/400)&1); - global.shake_view = 16; + stage_shake_view(160); play_sound("boom"); for(i = 0; i < c; i++) { @@ -1810,10 +1814,6 @@ void elly_lhc(Boss *b, int t) { .args = { cexp(2.0*I*_i), 3 }, ); } - - FROM_TO(300, 10000, 400) { - global.shake_view = 0; - } } static int baryon_explode(Enemy *e, int t) { @@ -1822,7 +1822,7 @@ static int baryon_explode(Enemy *e, int t) { free_ref(e->args[1]); petal_explosion(24, e->pos); play_sound("boom"); - global.shake_view = fmaxf(15, global.shake_view); + stage_shake_view(15); for(uint i = 0; i < 3; ++i) { PARTICLE( @@ -2071,8 +2071,6 @@ static void elly_baryon_explode(Boss *b, int t) { GO_TO(b, BOSS_DEFAULT_GO_POS, 0.05); - global.shake_view_fade = 0.5; - AT(20) { set_baryon_rule(baryon_explode); } @@ -2084,7 +2082,8 @@ static void elly_baryon_explode(Boss *b, int t) { FROM_TO(0, 200, 1) { // tsrand_fill(2); // petal_explosion(1, b->pos + 100*afrand(0)*cexp(2.0*I*M_PI*afrand(1))); - global.shake_view = fmaxf(global.shake_view, 5 * _i / 200.0f); + // global.shake_view = fmaxf(global.shake_view, 5 * _i / 200.0f); + stage_shake_view(_i / 200.0f); if(_i > 30) { play_loop("charge_generic"); @@ -2093,8 +2092,7 @@ static void elly_baryon_explode(Boss *b, int t) { AT(200) { tsrand_fill(2); - global.shake_view += 30; - global.shake_view_fade = 0.05; + stage_shake_view(40); play_sound("boom"); petal_explosion(100, b->pos + 100*afrand(0)*cexp(2.0*I*M_PI*afrand(1))); enemy_kill_all(&global.enemies); @@ -2635,7 +2633,7 @@ static void elly_toe_laser_logic(Laser *l, int t) { // void elly_theory(Boss *b, int time) { if(time == EVENT_BIRTH) { - global.shake_view = 10; + stage_shake_view(50); boss_set_portrait(b, "elly", "beaten", "shouting"); return; } @@ -2650,7 +2648,6 @@ void elly_theory(Boss *b, int time) { AT(0) { assert(cabs(b->pos - ELLY_TOE_TARGET_POS) < 1); b->pos = ELLY_TOE_TARGET_POS; - global.shake_view = 0; elly_clap(b,50000); } @@ -2737,16 +2734,14 @@ void elly_theory(Boss *b, int time) { AT(fermiontime) { play_sound("charge_generic"); - global.shake_view=10; - global.shake_view_fade=1; + stage_shake_view(10); } AT(symmetrytime) { play_sound("charge_generic"); play_sound("boom"); stagetext_add("Symmetry broken!", VIEWPORT_W/2+I*VIEWPORT_H/4, ALIGN_CENTER, get_font("big"), RGB(1,1,1), 0,100,10,20); - global.shake_view=10; - global.shake_view_fade=1; + stage_shake_view(10); PARTICLE( .sprite = "blast", @@ -2774,16 +2769,14 @@ void elly_theory(Boss *b, int time) { AT(yukawatime) { play_sound("charge_generic"); stagetext_add("Coupling the Higgs!", VIEWPORT_W/2+I*VIEWPORT_H/4, ALIGN_CENTER, get_font("big"), RGB(1,1,1), 0,100,10,20); - global.shake_view=10; - global.shake_view_fade=1; + stage_shake_view(10); } AT(breaktime) { play_sound("charge_generic"); stagetext_add("Perturbation theory", VIEWPORT_W/2+I*VIEWPORT_H/4, ALIGN_CENTER, get_font("big"), RGB(1,1,1), 0,100,10,20); stagetext_add("breaking down!", VIEWPORT_W/2+I*VIEWPORT_H/4+30*I, ALIGN_CENTER, get_font("big"), RGB(1,1,1), 0,100,10,20); - global.shake_view=10; - global.shake_view_fade=1; + stage_shake_view(10); } FROM_TO(higgstime,yukawatime+100,4+4*(time>symmetrytime)) { @@ -2962,7 +2955,6 @@ static void elly_begin_toe(Boss *b, int t) { start_fall_over(); stage_unlock_bgm("stage6boss_phase2"); stage_start_bgm("stage6boss_phase3"); - global.shake_view_fade = 0; } }