From 2ebbfc486454c249fb026b6845ee8b5e35e1c689 Mon Sep 17 00:00:00 2001 From: Erik Date: Tue, 14 Apr 2026 12:58:06 +0200 Subject: [PATCH] fix(physics): don't fall back to no-collision resolve on transition fail When FindTransitionalPosition fails (stuck in corner, too many steps), use the partially-resolved position instead of falling back to the simple Resolve which has no object collision. This prevents walking through objects when the transition can't find a clean path. The player now stops at corners instead of clipping through. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/AcDream.Core/Physics/PhysicsEngine.cs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/AcDream.Core/Physics/PhysicsEngine.cs b/src/AcDream.Core/Physics/PhysicsEngine.cs index 49c6e89..f966d10 100644 --- a/src/AcDream.Core/Physics/PhysicsEngine.cs +++ b/src/AcDream.Core/Physics/PhysicsEngine.cs @@ -329,18 +329,26 @@ public sealed class PhysicsEngine bool ok = transition.FindTransitionalPosition(this); + var sp = transition.SpherePath; + var ci = transition.CollisionInfo; + if (ok) { - var sp = transition.SpherePath; - var ci = transition.CollisionInfo; - bool onGround = ci.ContactPlaneValid || transition.ObjectInfo.State.HasFlag(ObjectInfoState.OnWalkable); return new ResolveResult(sp.CheckPos, sp.CheckCellId, onGround); } - // Transition failed — fall back to simple resolve. - return Resolve(currentPos, cellId, targetPos - currentPos, stepUpHeight); + // Transition failed (e.g., stuck in corner, too many steps). + // Use whatever position the transition reached (partial movement) + // instead of falling back to the no-collision Resolve. + // If CheckPos hasn't moved from CurPos, the player stays put — + // this is correct behavior when completely blocked. + bool partialOnGround = ci.ContactPlaneValid + || transition.ObjectInfo.State.HasFlag(ObjectInfoState.OnWalkable) + || isOnGround; + + return new ResolveResult(sp.CheckPos, sp.CheckCellId != 0 ? sp.CheckCellId : cellId, partialOnGround); } }