From 217fd7045ed54d5df7cdd13c9ac6a488e9237ead Mon Sep 17 00:00:00 2001 From: Erich Schubert Date: Sat, 9 Nov 2024 23:14:20 +0100 Subject: [PATCH] collision fixes --- src/collision.cpp | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/src/collision.cpp b/src/collision.cpp index 87c091515689d..355703ed785b9 100644 --- a/src/collision.cpp +++ b/src/collision.cpp @@ -33,7 +33,8 @@ struct NearbyCollisionInfo { position(pos), bouncy(bouncy), is_unloaded(is_ul), - is_step_up(false) + is_step_up(false), + has_collided(false) {} // object @@ -42,7 +43,8 @@ struct NearbyCollisionInfo { box(box), bouncy(bouncy), is_unloaded(false), - is_step_up(false) + is_step_up(false), + has_collided(false) {} inline bool isObject() const { return obj != nullptr; } @@ -50,9 +52,14 @@ struct NearbyCollisionInfo { ActiveObject *obj; aabb3f box; v3s16 position; + f32 distance; u8 bouncy; // bitfield to save space - bool is_unloaded:1, is_step_up:1; + bool is_unloaded:1, is_step_up:1, has_collided:1; + + bool operator<(const NearbyCollisionInfo& b) { + return distance < b.distance; + } }; // Helper functions: @@ -407,12 +414,19 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef, add_object_boxes(env, box_0, dtime, *pos_f, aspeed_f, self, cinfo); } + // Sort boxes by distance once, as we are more likely to collide with near boxes + v3f center_0 = box_0.getCenter(); + for (auto box = cinfo.begin(); box != cinfo.end(); box++) { + box->distance = (box->box.getCenter() - center_0).getLengthSQ(); + } + std::sort(cinfo.begin(), cinfo.end()); + // Collision detection f32 d = 0.0f; for (int loopcount = 0;; loopcount++) { if (loopcount >= 100) { warningstream << "collisionMoveSimple: Loop count exceeded, aborting to avoid infinite loop" << std::endl; - g_collision_problems_encountered = true; + g_collision_problems_encountered = true; // for unit tests break; } @@ -428,7 +442,7 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef, for (u32 boxindex = 0; boxindex < cinfo.size(); boxindex++) { const NearbyCollisionInfo &box_info = cinfo[boxindex]; // Ignore if already stepped up this nodebox. - if (box_info.is_step_up) + if (box_info.is_step_up || box_info.has_collided) continue; // Find nearest collision of the two boxes (raytracing-like) @@ -454,6 +468,7 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef, } // Otherwise, a collision occurred. NearbyCollisionInfo &nearest_info = cinfo[nearest_boxindex]; + nearest_info.has_collided = true; const aabb3f& cbox = nearest_info.box; //movingbox except moved to the horizontal position it would be after step up @@ -555,7 +570,7 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef, } result.collides = true; } else { - is_collision = false; + is_collision = false; // unreachable, actually } info.new_speed = *speed_f; @@ -595,7 +610,7 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef, cbox.MaxEdge.Z - d > box.MinEdge.Z && cbox.MinEdge.Z + d < box.MaxEdge.Z) { if (box_info.is_step_up) { - pos_f->Y += cbox.MaxEdge.Y - box.MinEdge.Y; + pos_f->Y += cbox.MaxEdge.Y - box.MinEdge.Y + 0.01f; // avoid glitching into the floor box = box_0; box.MinEdge += *pos_f; box.MaxEdge += *pos_f;