fp: Use correct 't' value for collision

This commit is contained in:
doyle 2023-09-17 22:22:04 +10:00
parent 0eca065c6e
commit 3637a24b87

View File

@ -477,8 +477,9 @@ void FP_GameUpdate(TELY_Platform *platform, FP_Game *game, TELY_Renderer *render
entity->velocity = (acceleration * t) + entity->velocity * 0.82f; entity->velocity = (acceleration * t) + entity->velocity * 0.82f;
Dqn_V2 delta_pos = (acceleration * 0.5f * t_squared) + (entity->velocity * t); Dqn_V2 delta_pos = (acceleration * 0.5f * t_squared) + (entity->velocity * t);
Dqn_V2 entity_new_pos = entity->local_pos + delta_pos;
Dqn_Rect entity_world_hit_box = FP_Game_CalcEntityWorldHitBox(game, entity->handle); Dqn_Rect entity_world_hit_box = FP_Game_CalcEntityWorldHitBox(game, entity->handle);
Dqn_V2 entity_pos = Dqn_Rect_Center(entity_world_hit_box);
Dqn_V2 entity_new_pos = entity_pos + delta_pos;
bool has_collision = false; bool has_collision = false;
for (FP_GameEntityIterator collider_it = {}; FP_Game_DFSPostOrderWalkEntityTree(game, &collider_it, game->root_entity); ) { for (FP_GameEntityIterator collider_it = {}; FP_Game_DFSPostOrderWalkEntityTree(game, &collider_it, game->root_entity); ) {
@ -487,53 +488,56 @@ void FP_GameUpdate(TELY_Platform *platform, FP_Game *game, TELY_Renderer *render
continue; continue;
// NOTE: Sweep collider with half the radius of the source entity // NOTE: Sweep collider with half the radius of the source entity
Dqn_Rect collider_world_hit_box = FP_Game_CalcEntityWorldHitBox(game, collider->handle); Dqn_Rect collider_world_hit_box = FP_Game_CalcEntityWorldHitBox(game, collider->handle);
collider_world_hit_box.pos -= (entity_world_hit_box.size * .5f); Dqn_Rect swept_collider_world_hit_box = collider_world_hit_box;
collider_world_hit_box.size += entity_world_hit_box.size; swept_collider_world_hit_box.pos -= (entity_world_hit_box.size * .5f);
swept_collider_world_hit_box.size += entity_world_hit_box.size;
if (!Dqn_Rect_ContainsPoint(collider_world_hit_box, entity_new_pos)) if (!Dqn_Rect_ContainsPoint(swept_collider_world_hit_box, entity_new_pos))
continue; continue;
Dqn_f32 collider_left_wall_x = swept_collider_world_hit_box.pos.x;
Dqn_f32 collider_right_wall_x = swept_collider_world_hit_box.pos.x + swept_collider_world_hit_box.size.w;
Dqn_f32 collider_top_wall_y = swept_collider_world_hit_box.pos.y;
Dqn_f32 collider_bottom_wall_y = swept_collider_world_hit_box.pos.y + swept_collider_world_hit_box.size.h;
Dqn_V2 o = entity_pos;
Dqn_V2 d = delta_pos;
// NOTE: Solve collision by determining the 't' value at which // NOTE: Solve collision by determining the 't' value at which
// we hit one of the walls of the collider and move the entity // we hit one of the walls of the collider and move the entity
// at exactly that point. // at exactly that point.
// O + td = x // O + td = x
// td = x - O // td = x - O
// t = (x - O) / d // t = (x - O) / d
Dqn_f32 collider_left_wall_x = collider_world_hit_box.pos.x; Dqn_f32 const SENTINEL_T = 999.f;
Dqn_f32 collider_right_wall_x = collider_world_hit_box.pos.x + collider_world_hit_box.size.w; Dqn_f32 earliest_t = SENTINEL_T;
Dqn_f32 collider_top_wall_y = collider_world_hit_box.pos.y;
Dqn_f32 collider_bottom_wall_y = collider_world_hit_box.pos.y + collider_world_hit_box.size.h;
Dqn_V2 o = entity_world_hit_box.pos;
Dqn_V2 d = delta_pos;
Dqn_f32 earliest_t = 999.f;
if (d.x != 0.f) { if (d.x != 0.f) {
Dqn_f32 left_t = (collider_left_wall_x - o.x / d.x); Dqn_f32 left_t = (collider_left_wall_x - o.x) / d.x;
Dqn_f32 right_t = (collider_right_wall_x - o.x / d.x); Dqn_f32 right_t = (collider_right_wall_x - o.x) / d.x;
if (left_t >= 0.f) if (left_t >= 0.f && left_t <= 1.f)
earliest_t = DQN_MIN(earliest_t, left_t); earliest_t = DQN_MIN(earliest_t, left_t);
if (right_t >= 0.f) if (right_t >= 0.f && right_t <= 1.f)
earliest_t = DQN_MIN(earliest_t, right_t); earliest_t = DQN_MIN(earliest_t, right_t);
} }
if (d.y != 0.f) { if (d.y != 0.f) {
Dqn_f32 top_t = (collider_top_wall_y - o.y / d.y); Dqn_f32 top_t = (collider_top_wall_y - o.y) / d.y;
Dqn_f32 bottom_t = (collider_bottom_wall_y - o.y / d.y); Dqn_f32 bottom_t = (collider_bottom_wall_y - o.y) / d.y;
if (top_t >= 0.f) if (top_t >= 0.f && top_t <= 1.f)
earliest_t = DQN_MIN(earliest_t, top_t); earliest_t = DQN_MIN(earliest_t, top_t);
if (bottom_t >= 0.f) if (bottom_t >= 0.f && bottom_t <= 1.f)
earliest_t = DQN_MIN(earliest_t, bottom_t); earliest_t = DQN_MIN(earliest_t, bottom_t);
} }
Dqn_V2 pos_just_before_collide = entity_world_hit_box.pos + (d * t); if (earliest_t != SENTINEL_T) {
Dqn_V2 new_delta_p = pos_just_before_collide - entity_world_hit_box.pos; Dqn_V2 pos_just_before_collide = entity_pos + (d * earliest_t);
entity->local_pos += new_delta_p; Dqn_V2 new_delta_p = pos_just_before_collide - entity_pos;
entity->velocity = {}; entity->local_pos += new_delta_p;
has_collision = true; entity->velocity = {};
has_collision = true;
}
} }
if (!has_collision) { if (!has_collision) {