Revamp screen shake system (#225)

This commit is contained in:
Andrei Alexeyev 2020-05-16 23:42:22 +03:00 committed by GitHub
parent 00e4837827
commit 7072fe447d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 88 additions and 95 deletions

View file

@ -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,

View file

@ -126,9 +126,6 @@ typedef struct {
ReplayMode replaymode;
ReplayStage *replay_stage;
float shake_view;
float shake_view_fade;
uint voltage_threshold;
RandomState rand_game;

View file

@ -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;

View file

@ -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; }) {

View file

@ -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");

View file

@ -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);

View file

@ -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;
}

View file

@ -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)

View file

@ -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);

View file

@ -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) {

View file

@ -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;
}
}