respond to collisions using callbacks rather than events
This commit is contained in:
parent
0ef72e1b23
commit
b66f130e9c
@ -22,8 +22,6 @@ enum entity_prop {
|
||||
ENTITY_PROP_MOUSE_JOINT,
|
||||
ENTITY_PROP_SENSOR,
|
||||
|
||||
ENTITY_PROP_HIT_EVENT,
|
||||
|
||||
ENTITY_PROP_PLAYER_CONTROLLED,
|
||||
ENTITY_PROP_CAMERA,
|
||||
ENTITY_PROP_CAMERA_ACTIVE,
|
||||
@ -128,11 +126,6 @@ struct entity {
|
||||
/* ENTITY_PROP_MOUSE_JOINT */
|
||||
struct phys_mouse_joint mouse_joint_data;
|
||||
|
||||
/* ====================================================================== */
|
||||
/* Hit event */
|
||||
|
||||
struct phys_hit_event hit_event;
|
||||
|
||||
/* ====================================================================== */
|
||||
/* Activation */
|
||||
|
||||
|
||||
113
src/game.c
113
src/game.c
@ -323,6 +323,50 @@ INTERNAL void release_entities_with_prop(enum entity_prop prop)
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Respond to physics collisions
|
||||
* ========================== */
|
||||
|
||||
INTERNAL PHYS_COLLISION_CALLBACK_FUNC_DEF(on_collision, array)
|
||||
{
|
||||
struct entity_store *store = G.tick.entity_store;
|
||||
struct entity *root = entity_from_handle(store, store->root);
|
||||
|
||||
for (u64 i = 0; i < array.count; ++i) {
|
||||
struct phys_collision_data *data = &array.a[i];
|
||||
|
||||
struct entity *e0 = entity_from_handle(store, data->e0);
|
||||
struct entity *e1 = entity_from_handle(store, data->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;
|
||||
(UNUSED)bullet;
|
||||
(UNUSED)target;
|
||||
|
||||
/* Disable bullet */
|
||||
entity_enable_prop(bullet, ENTITY_PROP_RELEASE_BEFORE_PUBLISH);
|
||||
entity_disable_prop(bullet, ENTITY_PROP_ACTIVE);
|
||||
|
||||
/* Create test blood */
|
||||
/* TODO: Remove this */
|
||||
{
|
||||
struct xform xf = XFORM_TRS(.t = data->point);
|
||||
struct entity *decal = entity_alloc(root);
|
||||
decal->sprite = sprite_tag_from_path(STR("res/graphics/blood.ase"));
|
||||
entity_set_xform(decal, xf);
|
||||
|
||||
entity_enable_prop(decal, ENTITY_PROP_PHYSICAL_KINEMATIC);
|
||||
decal->linear_velocity = v2_mul(v2_norm(data->normal), 0.5f);
|
||||
decal->angular_velocity = 1 - (((f32)sys_rand_u32() / (f32)U32_MAX) * 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Update
|
||||
* ========================== */
|
||||
@ -925,6 +969,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds)
|
||||
ctx.tick_id = G.tick.tick_id;
|
||||
ctx.store = store;
|
||||
ctx.contact_lookup = &G.contact_lookup;
|
||||
ctx.pre_solve_callback = on_collision;
|
||||
#if COLLIDER_DEBUG
|
||||
ctx.debug_lookup = &G.collision_debug_lookup;
|
||||
#endif
|
||||
@ -945,74 +990,6 @@ INTERNAL void game_update(struct game_cmd_array game_cmds)
|
||||
phys_step(&ctx, dt);
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Respond to hit events
|
||||
* ========================== */
|
||||
{
|
||||
struct temp_arena temp = arena_temp_begin(scratch.arena);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
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;
|
||||
|
||||
entity_enable_prop(bullet, ENTITY_PROP_RELEASE_BEFORE_PUBLISH);
|
||||
entity_disable_prop(bullet, ENTITY_PROP_ACTIVE);
|
||||
|
||||
/* Create test blood */
|
||||
/* TODO: Remove this */
|
||||
{
|
||||
struct xform xf = XFORM_TRS(.t = event->point);
|
||||
struct entity *decal = entity_alloc(root);
|
||||
decal->sprite = sprite_tag_from_path(STR("res/graphics/blood.ase"));
|
||||
entity_set_xform(decal, xf);
|
||||
|
||||
entity_enable_prop(decal, ENTITY_PROP_PHYSICAL_KINEMATIC);
|
||||
decal->linear_velocity = v2_mul(v2_norm(event->normal), 0.5f);
|
||||
decal->angular_velocity = 1 - (((f32)sys_rand_u32() / (f32)U32_MAX) * 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
arena_temp_end(temp);
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Initialize bullet kinematics from sources
|
||||
* ========================== */
|
||||
|
||||
44
src/phys.c
44
src/phys.c
@ -1,4 +1,6 @@
|
||||
#include "phys.h"
|
||||
#include "math.h"
|
||||
#include "scratch.h"
|
||||
#include "entity.h"
|
||||
|
||||
GLOBAL struct {
|
||||
@ -37,9 +39,11 @@ struct phys_startup_receipt phys_startup(void)
|
||||
* Contact
|
||||
* ========================== */
|
||||
|
||||
void phys_create_contacts(struct phys_ctx *ctx, f32 elapsed_dt)
|
||||
struct phys_collision_data_array phys_create_contacts(struct arena *arena, struct phys_ctx *ctx, f32 elapsed_dt)
|
||||
{
|
||||
__prof;
|
||||
struct phys_collision_data_array res = ZI;
|
||||
res.a = arena_dry_push(arena, struct phys_collision_data);
|
||||
u64 tick_id = ctx->tick_id;
|
||||
struct entity_lookup *contact_lookup = ctx->contact_lookup;
|
||||
struct entity_lookup *debug_lookup = ctx->debug_lookup;
|
||||
@ -115,23 +119,21 @@ void phys_create_contacts(struct phys_ctx *ctx, f32 elapsed_dt)
|
||||
struct phys_contact_constraint *constraint = NULL;
|
||||
if (collider_res.num_points > 0) {
|
||||
if (!entity_is_valid_and_active(constraint_ent)) {
|
||||
/* Create hit event */
|
||||
{
|
||||
struct entity *event = entity_alloc(root);
|
||||
entity_enable_prop(event, ENTITY_PROP_HIT_EVENT);
|
||||
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);
|
||||
/* Push collision data */
|
||||
if (ctx->pre_solve_callback || ctx->post_solve_callback) {
|
||||
struct phys_collision_data *data = arena_push_zero(arena, struct phys_collision_data);
|
||||
++res.count;
|
||||
data->e0 = e0->handle;
|
||||
data->e1 = e1->handle;
|
||||
data->normal = collider_res.normal;
|
||||
data->dt = elapsed_dt;
|
||||
|
||||
/* Calculate point */
|
||||
struct v2 point = collider_res.points[0].point;
|
||||
if (collider_res.num_points > 1) {
|
||||
point = v2_add(point, v2_mul(v2_sub(collider_res.points[1].point, point), 0.5f));
|
||||
}
|
||||
event->hit_event.point = point;
|
||||
data->point = point;
|
||||
|
||||
/* Calculate relative velocity */
|
||||
struct v2 vrel;
|
||||
@ -146,7 +148,7 @@ void phys_create_contacts(struct phys_ctx *ctx, f32 elapsed_dt)
|
||||
struct v2 vel1 = v2_add(v1, v2_perp_mul(vcp1, w1));
|
||||
vrel = v2_sub(vel0, vel1);
|
||||
}
|
||||
event->hit_event.vrel = vrel;
|
||||
data->vrel = vrel;
|
||||
}
|
||||
|
||||
/* Create constraint */
|
||||
@ -275,6 +277,7 @@ void phys_create_contacts(struct phys_ctx *ctx, f32 elapsed_dt)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void phys_prepare_contacts(struct phys_ctx *ctx)
|
||||
@ -1125,6 +1128,7 @@ void phys_step(struct phys_ctx *ctx, f32 timestep)
|
||||
f32 remaining_dt = timestep;
|
||||
while (remaining_dt > 0) {
|
||||
__profscope(step);
|
||||
struct temp_arena scratch = scratch_begin_no_conflict();
|
||||
/* TOI */
|
||||
f32 step_dt = remaining_dt;
|
||||
{
|
||||
@ -1141,13 +1145,18 @@ void phys_step(struct phys_ctx *ctx, f32 timestep)
|
||||
#endif
|
||||
}
|
||||
|
||||
phys_create_contacts(ctx, timestep - remaining_dt);
|
||||
struct phys_collision_data_array collision_data = phys_create_contacts(scratch.arena, ctx, timestep - remaining_dt);
|
||||
phys_create_mouse_joints(ctx);
|
||||
|
||||
phys_prepare_contacts(ctx);
|
||||
phys_prepare_motor_joints(ctx);
|
||||
phys_prepare_mouse_joints(ctx);
|
||||
|
||||
if (ctx->pre_solve_callback) {
|
||||
__profscope(pre_solve_callback);
|
||||
ctx->pre_solve_callback(collision_data);
|
||||
}
|
||||
|
||||
f32 substep_dt = step_dt / GAME_PHYSICS_SUBSTEPS;
|
||||
for (u32 i = 0; i < GAME_PHYSICS_SUBSTEPS; ++i) {
|
||||
__profscope(substep);
|
||||
@ -1169,5 +1178,12 @@ void phys_step(struct phys_ctx *ctx, f32 timestep)
|
||||
phys_solve_contacts(ctx, substep_dt, false); /* Relaxation */
|
||||
#endif
|
||||
}
|
||||
|
||||
if (ctx->post_solve_callback) {
|
||||
__profscope(post_solve_callback);
|
||||
ctx->post_solve_callback(collision_data);
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
}
|
||||
|
||||
43
src/phys.h
43
src/phys.h
@ -7,19 +7,8 @@
|
||||
struct entity_store;
|
||||
struct entity_lookup;
|
||||
|
||||
/* Structure containing data used for a single physics step */
|
||||
struct phys_ctx {
|
||||
u64 tick_id;
|
||||
struct entity_store *store;
|
||||
struct entity_lookup *contact_lookup;
|
||||
struct entity_lookup *debug_lookup;
|
||||
|
||||
struct v2 dbg_cursor_pos;
|
||||
b32 dbg_start_dragging;
|
||||
b32 dbg_stop_dragging;
|
||||
};
|
||||
|
||||
struct phys_hit_event {
|
||||
struct phys_collision_data {
|
||||
struct entity_handle constraint_ent;
|
||||
struct entity_handle e0;
|
||||
struct entity_handle e1;
|
||||
struct v2 point;
|
||||
@ -28,9 +17,29 @@ struct phys_hit_event {
|
||||
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;
|
||||
struct phys_collision_data_array {
|
||||
struct phys_collision_data *a;
|
||||
u64 count;
|
||||
};
|
||||
|
||||
struct phys_collision_data;
|
||||
#define PHYS_COLLISION_CALLBACK_FUNC_DEF(name, arg) void name(struct phys_collision_data_array arg)
|
||||
typedef PHYS_COLLISION_CALLBACK_FUNC_DEF(phys_collision_callback_func, data);
|
||||
|
||||
/* Structure containing data used for a single physics step */
|
||||
struct phys_ctx {
|
||||
u64 tick_id;
|
||||
struct entity_store *store;
|
||||
struct entity_lookup *contact_lookup;
|
||||
|
||||
phys_collision_callback_func *pre_solve_callback;
|
||||
phys_collision_callback_func *post_solve_callback;
|
||||
|
||||
struct entity_lookup *debug_lookup;
|
||||
struct v2 dbg_cursor_pos;
|
||||
b32 dbg_start_dragging;
|
||||
b32 dbg_stop_dragging;
|
||||
|
||||
};
|
||||
|
||||
/* ========================== *
|
||||
@ -97,7 +106,7 @@ struct phys_collision_debug {
|
||||
struct xform xf1;
|
||||
};
|
||||
|
||||
void phys_create_contacts(struct phys_ctx *ctx, f32 elapsed_dt);
|
||||
struct phys_collision_data_array phys_create_contacts(struct arena *arena, 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);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user