From bbd11d25260b4a34e094614cd79f74e439d10e21 Mon Sep 17 00:00:00 2001 From: jacob Date: Sat, 11 Jan 2025 15:09:14 -0600 Subject: [PATCH] sort hit events by dt to prevent out of order bullet hit processing --- src/entity.h | 1 - src/game.c | 67 ++++++++++++++++++++++++++++++++-------------------- src/phys.c | 7 +++--- src/phys.h | 10 ++++++-- 4 files changed, 53 insertions(+), 32 deletions(-) diff --git a/src/entity.h b/src/entity.h index 9a6d6fa1..206bf7ab 100644 --- a/src/entity.h +++ b/src/entity.h @@ -229,7 +229,6 @@ struct entity { struct v2 bullet_src_pos; struct v2 bullet_src_dir; f32 bullet_impulse; - b32 bullet_has_hit; /* Has the bullet hit a target this tick */ /* ====================================================================== */ /* Testing */ diff --git a/src/game.c b/src/game.c index be5b21cd..b5f0df2b 100644 --- a/src/game.c +++ b/src/game.c @@ -944,38 +944,51 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) /* ========================== * * Respond to hit events * ========================== */ + { + struct temp_arena temp = arena_temp_begin(scratch.arena); - 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_HIT_EVENT)) continue; + /* Sort hit events by dt (to ensure early time of impact collisions are processed first) */ + struct phys_hit_event_node *first_sorted = NULL; + 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_HIT_EVENT)) continue; + struct phys_hit_event *e = &ent->hit_event; + struct phys_hit_event_node *next = first_sorted; + struct phys_hit_event_node *prev = NULL; + while (next) { + if (e->dt < next->e->dt) { + break; + } + prev = next; + next = next->next; + } + struct phys_hit_event_node *n = arena_push_zero(temp.arena, struct phys_hit_event_node); + n->e = e; + n->next = next; + if (prev) { + prev->next = n; + } else { + first_sorted = n; + } + } - struct phys_hit_event *event = &ent->hit_event; + /* Process events */ + for (struct phys_hit_event_node *n = first_sorted; n; n = n->next) { + struct phys_hit_event *event = n->e; + struct entity *e0 = entity_from_handle(store, event->e0); + struct entity *e1 = entity_from_handle(store, event->e1); - struct entity *e0 = entity_from_handle(store, event->e0); - struct entity *e1 = entity_from_handle(store, event->e1); - - if (entity_is_valid_and_active(e0) && entity_is_valid_and_active(e1)) { - /* Bullet hit entity */ - if (entity_has_prop(e0, ENTITY_PROP_BULLET) || entity_has_prop(e1, ENTITY_PROP_BULLET)) { - struct entity *bullet = entity_has_prop(e0, ENTITY_PROP_BULLET) ? e0 : e1; - struct entity *target = e0 == bullet ? e1 : e0; - if (!bullet->bullet_has_hit) { - bullet->bullet_has_hit = true; + if (entity_is_valid_and_active(e0) && entity_is_valid_and_active(e1)) { + /* Bullet hit entity */ + if (entity_has_prop(e0, ENTITY_PROP_BULLET) || entity_has_prop(e1, ENTITY_PROP_BULLET)) { + struct entity *bullet = entity_has_prop(e0, ENTITY_PROP_BULLET) ? e0 : e1; + struct entity *target = e0 == bullet ? e1 : e0; (UNUSED)bullet; (UNUSED)target; - #if 0 - { - /* Set bullet position to hit position */ - struct xform xf = entity_get_xform(bullet); - xf.og = event->point; - entity_set_xform(bullet, xf); - /* Release after publish so user sees bullet in final postiion */ - entity_enable_prop(bullet, ENTITY_PROP_RELEASE_AFTER_PUBLISH); - } - #else + entity_enable_prop(bullet, ENTITY_PROP_RELEASE_BEFORE_PUBLISH); - #endif + entity_disable_prop(bullet, ENTITY_PROP_ACTIVE); /* Create test blood */ /* TODO: Remove this */ @@ -992,6 +1005,8 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) } } } + + arena_temp_end(temp); } /* ========================== * diff --git a/src/phys.c b/src/phys.c index 58b92c20..20d75bd3 100644 --- a/src/phys.c +++ b/src/phys.c @@ -37,7 +37,7 @@ struct phys_startup_receipt phys_startup(void) * Contact * ========================== */ -void phys_create_contacts(struct phys_ctx *ctx) +void phys_create_contacts(struct phys_ctx *ctx, f32 elapsed_dt) { u64 tick_id = ctx->tick_id; struct entity_lookup *contact_lookup = ctx->contact_lookup; @@ -121,6 +121,7 @@ void phys_create_contacts(struct phys_ctx *ctx) event->hit_event.e0 = e0->handle; event->hit_event.e1 = e1->handle; event->hit_event.normal = collider_res.normal; + event->hit_event.dt = elapsed_dt; entity_enable_prop(event, ENTITY_PROP_RELEASE_BEFORE_PUBLISH); entity_enable_prop(event, ENTITY_PROP_ACTIVE); @@ -1120,13 +1121,14 @@ void phys_step(struct phys_ctx *ctx, f32 timestep) const u32 max_iterations = 16; f32 earliest_toi = max_f32(phys_determine_earliest_toi_for_bullets(ctx, step_dt, tolerance, max_iterations), min_toi); step_dt = remaining_dt * earliest_toi; + remaining_dt -= step_dt; #else (UNUSED)toi; (UNUSED)determine_earliest_toi_for_bullets; #endif } - phys_create_contacts(ctx); + phys_create_contacts(ctx, timestep - remaining_dt); phys_create_mouse_joints(ctx); phys_prepare_contacts(ctx); @@ -1153,6 +1155,5 @@ void phys_step(struct phys_ctx *ctx, f32 timestep) phys_solve_contacts(ctx, substep_dt, false); /* Relaxation */ #endif } - remaining_dt -= step_dt; } } diff --git a/src/phys.h b/src/phys.h index 6e4f00c5..c572ff18 100644 --- a/src/phys.h +++ b/src/phys.h @@ -24,7 +24,13 @@ struct phys_hit_event { struct entity_handle e1; struct v2 point; struct v2 normal; - struct v2 vrel; /* Relative velocity */ + struct v2 vrel; /* Relative velocity */ + f32 dt; /* How much time elapsed in the step when this event occurred (this will equal the physics timestep unless an early time of impact collision occurred) */ +}; + +struct phys_hit_event_node { + struct phys_hit_event *e; + struct phys_hit_event_node *next; }; /* ========================== * @@ -91,7 +97,7 @@ struct phys_collision_debug { struct xform xf1; }; -void phys_create_contacts(struct phys_ctx *ctx); +void phys_create_contacts(struct phys_ctx *ctx, f32 elapsed_dt); void phys_prepare_contacts(struct phys_ctx *ctx); void phys_warm_start_contacts(struct phys_ctx *ctx); void phys_solve_contacts(struct phys_ctx *ctx, f32 dt, b32 apply_bias);