Collision: fix 'touching_ground' detection at high dtime

This commit is contained in:
SmallJoker 2024-11-05 19:07:30 +01:00 committed by Erich Schubert
parent c9085cdd81
commit 9a3b842221

View File

@ -109,6 +109,8 @@ CollisionAxis axisAlignedCollision(
if (speed.Y) {
distance = relbox.MaxEdge.Y - relbox.MinEdge.Y;
// FIXME: The dtime calculation is inaccurate without acceleration information.
// Exact formula: `dtime = (-vel ± sqrt(vel² + 2 * acc * distance)) / acc`
*dtime = distance / std::abs(speed.Y);
time = std::max(*dtime, 0.0f);
@ -526,15 +528,22 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
speed_f->X *= bounce;
} else {
speed_f->X = 0;
accel_f.X = 0;
accel_f.X = 0; // avoid colliding in the next interations
}
result.collides = true;
} else if (nearest_collided == COLLISION_AXIS_Y) {
if(bounce < -1e-4 && fabsf(speed_f->Y) > BS * 3) {
if (bounce < -1e-4 && fabsf(speed_f->Y) > BS * 3) {
speed_f->Y *= bounce;
} else {
if (speed_f->Y < 0.0f) {
// FIXME: This code is necessary until `axisAlignedCollision` takes acceleration
// into consideration for the time calculation. Otherwise, the colliding faces
// never line up, especially at high step (dtime) intervals.
result.touching_ground = true;
result.standing_on_object = nearest_info.isObject();
}
speed_f->Y = 0;
accel_f.Y = 0;
accel_f.Y = 0; // avoid colliding in the next interations
}
result.collides = true;
} else if (nearest_collided == COLLISION_AXIS_Z) {
@ -542,7 +551,7 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
speed_f->Z *= bounce;
} else {
speed_f->Z = 0;
accel_f.Z = 0;
accel_f.Z = 0; // avoid colliding in the next interations
}
result.collides = true;
} else {
@ -592,10 +601,10 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
box.MaxEdge += *pos_f;
}
if (std::fabs(cbox.MaxEdge.Y - box.MinEdge.Y) < 0.05f) {
// This is code is technically only required if `box_info.is_step_up == true`.
// However, players rely on this check/condition to climb stairs faster. See PR #10587.
result.touching_ground = true;
if (box_info.isObject())
result.standing_on_object = true;
result.standing_on_object = box_info.isObject();
}
}
}