start explosion work

This commit is contained in:
jacob 2025-05-16 08:15:21 -05:00
parent 2c0b2fcc36
commit 855fa051d0
7 changed files with 192 additions and 92 deletions

View File

@ -37,10 +37,10 @@
/* 64^2 = 4096 bins */ /* 64^2 = 4096 bins */
#define SPACE_CELL_BINS_SQRT (64) #define SPACE_CELL_BINS_SQRT (64)
#define SPACE_CELL_SIZE (1.0f) #define SPACE_CELL_SIZE (4)
#define SIM_TILES_PER_UNIT_SQRT (2) #define SIM_TILES_PER_UNIT_SQRT (2)
#define SIM_TILES_PER_CHUNK_SQRT (16) #define SIM_TILES_PER_CHUNK_SQRT (1)
#define SIM_TICKS_PER_SECOND 50 #define SIM_TICKS_PER_SECOND 50
//#define SIM_TIMESCALE 1 //#define SIM_TIMESCALE 1

View File

@ -1045,13 +1045,13 @@ f32 phys_determine_earliest_toi_for_bullets(struct phys_step_ctx *ctx, f32 step_
void phys_update_aabbs(struct phys_step_ctx *ctx) void phys_update_aabbs(struct phys_step_ctx *ctx)
{ {
__prof;
struct sim_snapshot *ss = ctx->sim_step_ctx->world; struct sim_snapshot *ss = ctx->sim_step_ctx->world;
struct space *space = ctx->sim_step_ctx->accel->space; struct space *space = ctx->sim_step_ctx->accel->space;
for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index) { for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index) {
struct sim_ent *ent = &ss->ents[sim_ent_index]; struct sim_ent *ent = &ss->ents[sim_ent_index];
if (!sim_ent_is_valid_and_active(ent)) continue; if (!sim_ent_is_valid_and_active(ent)) continue;
if (ent->local_collider.count <= 0) continue; if (ent->local_collider.count > 0) {
struct xform xf = sim_ent_get_xform(ent); struct xform xf = sim_ent_get_xform(ent);
struct space_entry *space_entry = space_entry_from_handle(space, ent->space_handle); struct space_entry *space_entry = space_entry_from_handle(space, ent->space_handle);
if (!space_entry->valid) { if (!space_entry->valid) {
@ -1061,6 +1061,7 @@ void phys_update_aabbs(struct phys_step_ctx *ctx)
struct aabb aabb = collider_aabb_from_collider(&ent->local_collider, xf); struct aabb aabb = collider_aabb_from_collider(&ent->local_collider, xf);
space_entry_update_aabb(space_entry, aabb); space_entry_update_aabb(space_entry, aabb);
} }
}
} }
/* ========================== * /* ========================== *

View File

@ -141,6 +141,7 @@ enum sim_control_flag {
SIM_CONTROL_FLAG_CLEAR_ALL = 1 << 2, SIM_CONTROL_FLAG_CLEAR_ALL = 1 << 2,
SIM_CONTROL_FLAG_SPAWN_TEST = 1 << 3, SIM_CONTROL_FLAG_SPAWN_TEST = 1 << 3,
SIM_CONTROL_FLAG_TILE_TEST = 1 << 4, SIM_CONTROL_FLAG_TILE_TEST = 1 << 4,
SIM_CONTROL_FLAG_EXPLODE_TEST = 1 << 5,
}; };
struct sim_control { struct sim_control {

View File

@ -47,6 +47,9 @@ enum sim_ent_prop {
SEPROP_TRIGGERED_THIS_TICK, SEPROP_TRIGGERED_THIS_TICK,
SEPROP_TRIGGER_NEXT_TICK, SEPROP_TRIGGER_NEXT_TICK,
SEPROP_EXPLOSION,
SEPROP_EXPLOSION_STARTED,
SEPROP_BULLET, SEPROP_BULLET,
SEPROP_TRACER, SEPROP_TRACER,
@ -293,8 +296,14 @@ struct sim_ent {
struct v2 bullet_src_dir; struct v2 bullet_src_dir;
f32 bullet_impulse; f32 bullet_impulse;
f32 bullet_knockback; f32 bullet_knockback;
f32 bullet_impact_explosion_radius;
b32 bullet_has_hit; b32 bullet_has_hit;
/* ====================================================================== */
/* Explosion */
f32 explosion_radius;
/* ====================================================================== */ /* ====================================================================== */
/* Tracer */ /* Tracer */

View File

@ -23,7 +23,7 @@
struct sim_accel sim_accel_alloc(void) struct sim_accel sim_accel_alloc(void)
{ {
struct sim_accel accel = ZI; struct sim_accel accel = ZI;
accel.space = space_alloc(1, 256); accel.space = space_alloc(SPACE_CELL_SIZE, SPACE_CELL_BINS_SQRT);
return accel; return accel;
} }
@ -94,8 +94,10 @@ INTERNAL struct sim_ent *spawn_test_employee(struct sim_step_ctx *ctx)
sim_ent_set_xform(e, xf); sim_ent_set_xform(e, xf);
#if 0
e->linear_ground_friction = 250; e->linear_ground_friction = 250;
e->angular_ground_friction = 200; e->angular_ground_friction = 200;
#endif
e->friction = 0; e->friction = 0;
@ -187,7 +189,9 @@ INTERNAL void spawn_test_entities(struct sim_step_ctx *ctx, struct v2 offset)
/* Enemy */ /* Enemy */
if (ctx->is_master) { if (ctx->is_master) {
struct sim_ent *e = spawn_test_employee(ctx); struct sim_ent *e = spawn_test_employee(ctx);
(UNUSED)e; struct xform xf = sim_ent_get_xform(e);
xf.og = offset;
sim_ent_set_xform(e, xf);
} }
/* Big box */ /* Big box */
@ -253,32 +257,22 @@ INTERNAL void test_clear_level(struct sim_step_ctx *ctx)
* Respond to physics collisions * Respond to physics collisions
* ========================== */ * ========================== */
INTERNAL PHYS_COLLISION_CALLBACK_FUNC_DEF(on_collision, collision_data_array, step_ctx) INTERNAL void on_collision(struct sim_ent *e0, struct sim_ent *e1, struct phys_collision_data *data, struct sim_step_ctx *step_ctx)
{ {
struct sim_snapshot *world = step_ctx->world; struct sim_snapshot *world = step_ctx->world;
struct sim_ent *root = sim_ent_from_id(world, SIM_ENT_ROOT_ID); struct sim_ent *root = sim_ent_from_id(world, SIM_ENT_ROOT_ID);
for (u64 i = 0; i < collision_data_array.count; ++i) {
struct phys_collision_data *data = &collision_data_array.a[i];
struct phys_contact_constraint *constraint = data->constraint; struct phys_contact_constraint *constraint = data->constraint;
struct sim_ent *e0 = sim_ent_from_id(world, data->e0);
struct sim_ent *e1 = sim_ent_from_id(world, data->e1);
if (sim_ent_should_simulate(e0) && sim_ent_should_simulate(e1)) { if (sim_ent_should_simulate(e0) && sim_ent_should_simulate(e1)) {
/* Bullet hit entity */
if (sim_ent_has_prop(e0, SEPROP_BULLET) || sim_ent_has_prop(e1, SEPROP_BULLET)) { /* Bullet impact */
if (sim_ent_has_prop(e0, SEPROP_BULLET)) {
struct v2 normal = data->normal; /* Impact normal */ struct v2 normal = data->normal; /* Impact normal */
struct v2 vrel = v2_neg(data->vrel); /* Impact velocity */ struct v2 vrel = v2_neg(data->vrel); /* Impact velocity */
struct sim_ent *target = e0; struct sim_ent *bullet = e0;
struct sim_ent *bullet = e1; struct sim_ent *target = e1;
if (sim_ent_has_prop(e0, SEPROP_BULLET)) {
target = e1;
bullet = e0;
normal = v2_neg(normal);
vrel = v2_neg(vrel);
}
struct sim_ent *src = sim_ent_from_id(world, bullet->bullet_src); struct sim_ent *src = sim_ent_from_id(world, bullet->bullet_src);
if (bullet->bullet_has_hit || sim_ent_id_eq(src->top, target->top)) { if (bullet->bullet_has_hit || sim_ent_id_eq(src->top, target->top)) {
@ -302,10 +296,6 @@ INTERNAL PHYS_COLLISION_CALLBACK_FUNC_DEF(on_collision, collision_data_array, st
struct v2 knockback = v2_mul(v2_norm(vrel), bullet->bullet_knockback); struct v2 knockback = v2_mul(v2_norm(vrel), bullet->bullet_knockback);
sim_ent_apply_linear_impulse(target, knockback, point); sim_ent_apply_linear_impulse(target, knockback, point);
/* Explode */
//if (sim_ent_has_prop(bullet, SEPROP_EXPLODE_ON_IMPACT)) {
//}
/* Create test blood */ /* Create test blood */
/* TODO: Remove this */ /* TODO: Remove this */
{ {
@ -331,12 +321,37 @@ INTERNAL PHYS_COLLISION_CALLBACK_FUNC_DEF(on_collision, collision_data_array, st
decal->angular_damping = 5.0f; decal->angular_damping = 5.0f;
} }
/* Create explosion */
if (bullet->bullet_impact_explosion_radius > 0) {
struct sim_ent *exp = sim_ent_alloc_sync_src(root);
sim_ent_set_xform(exp, XFORM_POS(point));
sim_ent_enable_prop(exp, SEPROP_SENSOR);
sim_ent_enable_prop(exp, SEPROP_EXPLOSION);
exp->explosion_radius = bullet->bullet_impact_explosion_radius;
}
/* Update bullet */ /* Update bullet */
bullet->bullet_has_hit = true; bullet->bullet_has_hit = true;
//sim_ent_enable_prop(bullet, SEPROP_RELEASE); sim_ent_enable_prop(bullet, SEPROP_RELEASE);
} }
} }
} }
}
INTERNAL PHYS_COLLISION_CALLBACK_FUNC_DEF(pre_solve_callback, collision_data_array, step_ctx)
{
struct sim_snapshot *world = step_ctx->world;
for (u64 i = 0; i < collision_data_array.count; ++i) {
struct phys_collision_data *data = &collision_data_array.a[i];
struct sim_ent *e0 = sim_ent_from_id(world, data->e0);
struct sim_ent *e1 = sim_ent_from_id(world, data->e1);
if (sim_ent_is_valid_and_active(e0) && sim_ent_is_valid_and_active(e1)) {
on_collision(e0, e1, data, step_ctx);
if (sim_ent_is_valid_and_active(e1) && sim_ent_is_valid_and_active(e0)) {
on_collision(e1, e0, data, step_ctx);
}
}
} }
} }
@ -558,12 +573,25 @@ void sim_step(struct sim_step_ctx *ctx)
if (!(old_control.flags & SIM_CONTROL_FLAG_SPAWN_TEST)) { if (!(old_control.flags & SIM_CONTROL_FLAG_SPAWN_TEST)) {
logf_info("Spawning (test)"); logf_info("Spawning (test)");
u32 count = 1; u32 count = 1;
f32 spread = 1; f32 spread = 0;
for (u32 j = 0; j < count; ++j) { for (u32 j = 0; j < count; ++j) {
spawn_test_entities(ctx, V2(0, (((f32)j / (f32)count) - 0.5) * spread)); struct v2 pos = player->player_cursor_pos;
pos.y += (((f32)j / (f32)count) - 0.5) * spread;
spawn_test_entities(ctx, pos);
} }
} }
} }
if (flags & SIM_CONTROL_FLAG_EXPLODE_TEST) {
if (!(old_control.flags & SIM_CONTROL_FLAG_EXPLODE_TEST)) {
logf_info("Explosion (test)");
struct sim_ent *exp = sim_ent_alloc_sync_src(root);
sim_ent_set_xform(exp, XFORM_POS(player->player_cursor_pos));
sim_ent_enable_prop(exp, SEPROP_EXPLOSION);
exp->explosion_radius = 50;
}
}
if (flags & SIM_CONTROL_FLAG_TILE_TEST) { if (flags & SIM_CONTROL_FLAG_TILE_TEST) {
#if 0 #if 0
if (is_master) { if (is_master) {
@ -901,7 +929,7 @@ void sim_step(struct sim_step_ctx *ctx)
bullet->bullet_src_dir = rel_dir; bullet->bullet_src_dir = rel_dir;
//bullet->bullet_impulse = 0.75f; //bullet->bullet_impulse = 0.75f;
bullet->bullet_impulse = 2.0f; bullet->bullet_impulse = 2.0f;
bullet->bullet_knockback = 10; //bullet->bullet_knockback = 10;
bullet->mass_unscaled = 0.04f; bullet->mass_unscaled = 0.04f;
bullet->inertia_unscaled = 0.00001f; bullet->inertia_unscaled = 0.00001f;
bullet->layer = SIM_LAYER_BULLETS; bullet->layer = SIM_LAYER_BULLETS;
@ -951,6 +979,7 @@ void sim_step(struct sim_step_ctx *ctx)
//bullet->bullet_impulse = 0.75f; //bullet->bullet_impulse = 0.75f;
bullet->bullet_impulse = 0.75; bullet->bullet_impulse = 0.75;
bullet->bullet_knockback = 10; bullet->bullet_knockback = 10;
bullet->bullet_impact_explosion_radius = 1.0;
bullet->mass_unscaled = 0.04f; bullet->mass_unscaled = 0.04f;
bullet->inertia_unscaled = 0.00001f; bullet->inertia_unscaled = 0.00001f;
bullet->layer = SIM_LAYER_BULLETS; bullet->layer = SIM_LAYER_BULLETS;
@ -1199,10 +1228,64 @@ void sim_step(struct sim_step_ctx *ctx)
{ {
struct phys_step_ctx phys = ZI; struct phys_step_ctx phys = ZI;
phys.sim_step_ctx = ctx; phys.sim_step_ctx = ctx;
phys.pre_solve_callback = on_collision; phys.pre_solve_callback = pre_solve_callback;
phys_step(&phys, sim_dt); phys_step(&phys, sim_dt);
} }
/* ========================== *
* Update explosions
* ========================== */
for (u64 ent_index = 0; ent_index < world->num_ents_reserved; ++ent_index) {
struct sim_ent *ent = &world->ents[ent_index];
if (!sim_ent_should_simulate(ent)) continue;
if (sim_ent_has_prop(ent, SEPROP_EXPLOSION)) {
struct xform xf = sim_ent_get_xform(ent);
if (!sim_ent_has_prop(ent, SEPROP_EXPLOSION_STARTED)) {
f32 radius = ent->explosion_radius;
sim_ent_enable_prop(ent, SEPROP_EXPLOSION_STARTED);
struct collider_shape origin_collider = ZI;
origin_collider.count = 1;
struct aabb aabb = ZI;
{
struct collider_shape radius_collider = ZI;
radius_collider.radius = radius;
radius_collider.count = 1;
ent->local_collider = radius_collider;
aabb = collider_aabb_from_collider(&radius_collider, xf);
}
/* Find ents in blast range */
struct space_iter iter = space_iter_begin_aabb(ctx->accel->space, aabb);
struct space_entry *space_entry;
while ((space_entry = space_iter_next(&iter))) {
struct sim_ent *victim = sim_ent_from_id(world, space_entry->ent);
if (sim_ent_should_simulate(victim) && sim_ent_has_prop(victim, SEPROP_PHYSICAL_DYNAMIC) && !sim_ent_id_eq(ent->id, victim->id)) {
struct xform victim_xf = sim_ent_get_xform(victim);
struct collider_closest_points_result closest_points = collider_closest_points(&origin_collider, &victim->local_collider, xf, victim_xf);
struct v2 dir = v2_sub(closest_points.p1, closest_points.p0);
f32 distance = v2_len(dir);
/* TODO: Blast obstruction */
if (distance <= radius) {
/* TODO: Exponential decay */
//f32 ratio = (radius - distance) / radius;
//f32 strength = 100;
//struct v2 impulse = v2_with_len(dir, strength * ratio);
struct v2 impulse = V2(-100, 0);
//sim_ent_apply_linear_impulse(victim, impulse, closest_points.p1);
sim_ent_apply_linear_impulse_to_center(victim, impulse);
}
}
}
space_iter_end(iter);
}
}
}
/* ========================== * /* ========================== *
* Update tracers * Update tracers
* ========================== */ * ========================== */

View File

@ -145,6 +145,7 @@ GLOBAL READONLY enum user_bind_kind g_binds[SYS_BTN_COUNT] = {
[SYS_BTN_M4] = USER_BIND_KIND_TILE_TEST, [SYS_BTN_M4] = USER_BIND_KIND_TILE_TEST,
[SYS_BTN_M2] = USER_BIND_KIND_DEBUG_DRAG, [SYS_BTN_M2] = USER_BIND_KIND_DEBUG_DRAG,
[SYS_BTN_F] = USER_BIND_KIND_DEBUG_EXPLODE,
[SYS_BTN_C] = USER_BIND_KIND_DEBUG_CLEAR, [SYS_BTN_C] = USER_BIND_KIND_DEBUG_CLEAR,
[SYS_BTN_V] = USER_BIND_KIND_DEBUG_SPAWN, [SYS_BTN_V] = USER_BIND_KIND_DEBUG_SPAWN,
[SYS_BTN_N] = USER_BIND_KIND_DEBUG_STEP, [SYS_BTN_N] = USER_BIND_KIND_DEBUG_STEP,
@ -1590,9 +1591,10 @@ INTERNAL void user_update(void)
struct bind_state drag_state = G.bind_states[USER_BIND_KIND_DEBUG_DRAG]; struct bind_state drag_state = G.bind_states[USER_BIND_KIND_DEBUG_DRAG];
struct bind_state clear_state = G.bind_states[USER_BIND_KIND_DEBUG_CLEAR]; struct bind_state clear_state = G.bind_states[USER_BIND_KIND_DEBUG_CLEAR];
struct bind_state spawn_state = G.bind_states[USER_BIND_KIND_DEBUG_SPAWN]; struct bind_state spawn_state = G.bind_states[USER_BIND_KIND_DEBUG_SPAWN];
struct bind_state tile_state = G.bind_states[USER_BIND_KIND_TILE_TEST];
struct bind_state pause_state = G.bind_states[USER_BIND_KIND_DEBUG_PAUSE]; struct bind_state pause_state = G.bind_states[USER_BIND_KIND_DEBUG_PAUSE];
struct bind_state step_state = G.bind_states[USER_BIND_KIND_DEBUG_STEP]; struct bind_state step_state = G.bind_states[USER_BIND_KIND_DEBUG_STEP];
struct bind_state tile_state = G.bind_states[USER_BIND_KIND_TILE_TEST];
struct bind_state explode_state = G.bind_states[USER_BIND_KIND_DEBUG_EXPLODE];
if (fire_state.num_presses || fire_state.is_held) { if (fire_state.num_presses || fire_state.is_held) {
control.flags |= SIM_CONTROL_FLAG_FIRE; control.flags |= SIM_CONTROL_FLAG_FIRE;
@ -1609,6 +1611,9 @@ INTERNAL void user_update(void)
if (tile_state.num_presses) { if (tile_state.num_presses) {
control.flags |= SIM_CONTROL_FLAG_TILE_TEST; control.flags |= SIM_CONTROL_FLAG_TILE_TEST;
} }
if (explode_state.num_presses) {
control.flags |= SIM_CONTROL_FLAG_EXPLODE_TEST;
}
if (pause_state.num_presses) { if (pause_state.num_presses) {
atomic_i32_eval_xor(&G.user_paused, 1); atomic_i32_eval_xor(&G.user_paused, 1);

View File

@ -36,6 +36,7 @@ enum user_bind_kind {
USER_BIND_KIND_DEBUG_PAUSE, USER_BIND_KIND_DEBUG_PAUSE,
USER_BIND_KIND_DEBUG_STEP, USER_BIND_KIND_DEBUG_STEP,
USER_BIND_KIND_DEBUG_DRAG, USER_BIND_KIND_DEBUG_DRAG,
USER_BIND_KIND_DEBUG_EXPLODE,
USER_BIND_KIND_FULLSCREEN, USER_BIND_KIND_FULLSCREEN,
USER_BIND_KIND_ZOOM_IN, USER_BIND_KIND_ZOOM_IN,
USER_BIND_KIND_ZOOM_OUT, USER_BIND_KIND_ZOOM_OUT,