From 4c194d3b3919d5c4cc1def26b3b017b50f6a7175 Mon Sep 17 00:00:00 2001 From: jacob Date: Tue, 14 Jan 2025 17:06:25 -0600 Subject: [PATCH] camera shake --- src/entity.h | 12 ++++++++++++ src/game.c | 50 ++++++++++++++++++++++++++++++++++++++++++++------ src/user.c | 47 ++++++++++++++++++++++------------------------- 3 files changed, 78 insertions(+), 31 deletions(-) diff --git a/src/entity.h b/src/entity.h index eb818a3c..ee21dbde 100644 --- a/src/entity.h +++ b/src/entity.h @@ -34,6 +34,8 @@ enum entity_prop { ENTITY_PROP_BULLET, ENTITY_PROP_TRACER, + ENTITY_PROP_QUAKE, + ENTITY_PROP_ATTACHED, /* Test props */ @@ -246,6 +248,14 @@ struct entity { struct v2 tracer_gradient_start; struct v2 tracer_gradient_end; + /* ====================================================================== */ + /* Quake */ + + /* ENTITY_PROP_QUAKE */ + + f32 quake_intensity; + f32 quake_fade; /* How much intensity to lose per second */ + /* ====================================================================== */ /* Testing */ @@ -269,6 +279,8 @@ struct entity { u32 camera_lerp_continuity_gen; struct xform camera_xform_target; /* Calculated from camera_follow */ u32 camera_applied_lerp_continuity_gen_plus_one; /* Calculated */ + + f32 shake; }; struct entity_array { diff --git a/src/game.c b/src/game.c index 865caa59..0c27da2f 100644 --- a/src/game.c +++ b/src/game.c @@ -222,7 +222,7 @@ INTERNAL void spawn_test_entities(void) } /* Enemy */ -#if 0 +#if 1 { struct entity *e = entity_alloc(root); @@ -1144,23 +1144,33 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) tracer->tracer_gradient_end = pos; tracer->tracer_gradient_start = v2_sub(pos, v2_mul(ent->linear_velocity, tracer->tracer_fade_duration)); } + + /* Spawn quake */ + { + struct entity *quake = entity_alloc(root); + entity_set_xform(quake, XFORM_POS(pos)); + quake->quake_intensity = 0.02f; + quake->quake_fade = quake->quake_intensity / 0.01f; + entity_enable_prop(quake, ENTITY_PROP_QUAKE); + } } } /* ========================== * - * Update camera position + * Update cameras * ========================== */ for (u64 entity_index = 0; entity_index < store->reserved; ++entity_index) { struct entity *ent = &store->entities[entity_index]; if (!entity_is_valid_and_active(ent)) continue; + if (!entity_has_prop(ent, ENTITY_PROP_CAMERA)) continue; + + struct xform xf = entity_get_xform(ent); /* Camera follow */ - if (entity_has_prop(ent, ENTITY_PROP_CAMERA)) { + { struct entity *follow = entity_from_handle(store, ent->camera_follow); - struct xform xf = entity_get_xform(ent); - f32 aspect_ratio = 1.0; { struct xform quad_xf = xform_mul(entity_get_xform(ent), ent->camera_quad_xform); @@ -1185,7 +1195,35 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) xf = ent->camera_xform_target; } ent->camera_applied_lerp_continuity_gen_plus_one = ent->camera_lerp_continuity_gen + 1; - entity_set_xform(ent, xf); + } + + /* Camera shake */ + { + /* TODO: Update based on distance to quake */ + ent->shake = 0; + for (u64 quake_ent_index = 0; quake_ent_index < store->reserved; ++quake_ent_index) { + struct entity *quake = &store->entities[quake_ent_index]; + if (!entity_is_valid_and_active(quake)) continue; + if (!entity_has_prop(quake, ENTITY_PROP_QUAKE)) continue; + ent->shake += quake->quake_intensity; + } + } + + entity_set_xform(ent, xf); + } + + /* ========================== * + * Update quakes + * ========================== */ + + for (u64 entity_index = 0; entity_index < store->reserved; ++entity_index) { + struct entity *ent = &store->entities[entity_index]; + if (!entity_is_valid_and_active(ent)) continue; + if (!entity_has_prop(ent, ENTITY_PROP_QUAKE)) continue; + + ent->quake_intensity = max_f32(0, ent->quake_intensity - (ent->quake_fade * dt)); + if (ent->quake_intensity <= 0) { + entity_enable_prop(ent, ENTITY_PROP_RELEASE_NEXT_TICK); } } diff --git a/src/user.c b/src/user.c index 7ae10fbd..4bc95d68 100644 --- a/src/user.c +++ b/src/user.c @@ -388,10 +388,6 @@ INTERNAL void pubilsh_game_cmds(struct game_cmd_list *list) scratch_end(scratch); } -/* ========================== * - * Update - * ========================== */ - /* TODO: remove this (testing) */ INTERNAL void debug_draw_xform(struct xform xf, u32 color_x, u32 color_y) { @@ -432,24 +428,9 @@ INTERNAL void debug_draw_movement(struct entity *ent) draw_solid_arrow_ray(G.viewport_canvas, pos, vel_ray, thickness, arrow_len, color_vel); } - - - - - - - - - - - - - - - - - - +/* ========================== * + * Update + * ========================== */ INTERNAL void user_update(void) { @@ -541,6 +522,7 @@ INTERNAL void user_update(void) e->camera_quad_xform = xform_lerp(e0->camera_quad_xform, e1->camera_quad_xform, tick_blend); e->camera_xform_target = xform_lerp(e0->camera_xform_target, e1->camera_xform_target, tick_blend); + e->shake = math_lerp(e0->shake, e1->shake, tick_blend); e->tracer_gradient_start = v2_lerp(e0->tracer_gradient_start, e1->tracer_gradient_start, tick_blend); e->tracer_gradient_end = v2_lerp(e0->tracer_gradient_end, e1->tracer_gradient_end, tick_blend); @@ -693,9 +675,24 @@ INTERNAL void user_update(void) G.debug_camera = !G.debug_camera; } + /* ========================== * + * Apply shake + * ========================== */ + + for (u64 entity_index = 0; entity_index < store->reserved; ++entity_index) { + struct entity *ent = &store->entities[entity_index]; + if (!entity_is_valid_and_active(ent)) continue; + if (ent->shake <= 0) continue; + + f32 shake = ent->shake; + + struct xform xf = entity_get_xform(ent); + xf.og = v2_add(xf.og, v2_mul(v2_from_angle(sys_rand_f32(0, TAU)), shake)); + entity_set_xform(ent, xf); + } /* ========================== * - * Update viewport + * Update viewport from camera * ========================== */ /* Calculate screen viewport dimensions */ @@ -734,7 +731,7 @@ INTERNAL void user_update(void) G.viewport_cursor = v2_sub(G.screen_cursor, G.viewport_screen_offset); /* ========================== * - * Update view + * Update view from camera * ========================== */ if (G.debug_camera) { @@ -798,7 +795,7 @@ INTERNAL void user_update(void) G.world_cursor = xform_invert_mul_v2(G.world_view, G.viewport_cursor); /* ========================== * - * Update listener + * Update listener from view * ========================== */ {