From c3d9c06118fcae5439d1bf1b92597a5382e3b5c5 Mon Sep 17 00:00:00 2001 From: MelekTaus Moribundus Date: Sun, 12 Jul 2026 15:44:27 +0200 Subject: [PATCH] Fix wall-climb jitter in pinches between two surfaces The center re-probe could miss the still-touching climbed face and adopt a hit on a different collider much farther out, flipping the wall normal and letting the standoff servo drag the capsule across the pinch every other frame. When the probed gap is well beyond the standoff and the full-capsule span still holds a steep surface meaningfully closer, keep that contact instead of defecting to the far hit. Co-Authored-By: Claude Fable 5 --- .../Controller/PlayerCharacterController.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Assets/Scripts/Components/Controller/PlayerCharacterController.cs b/Assets/Scripts/Components/Controller/PlayerCharacterController.cs index a43e198..7e782c9 100644 --- a/Assets/Scripts/Components/Controller/PlayerCharacterController.cs +++ b/Assets/Scripts/Components/Controller/PlayerCharacterController.cs @@ -740,6 +740,21 @@ public class PlayerCharacterController : MonoBehaviour } else if (found) { + // Pinch between two surfaces: the center band can miss the (still touching) climbed + // face and catch a DIFFERENT collider much farther out. Adopting that hit flips the + // normal and the standoff servo drags the capsule across the pinch — oscillating + // every other frame with the span probe snapping it back. When the full-capsule span + // still holds a steep surface meaningfully closer, THAT contact is the climbed face: + // keep it instead of defecting to the far hit. + if (gap > (_controller.skinWidth + 0.05f) * CapsuleScale + && ProbeWallSpan(out Vector3 heldNormal, out float heldGap) + && heldGap + 0.05f * CapsuleScale < gap + && Vector3.Angle(heldNormal, Vector3.up) >= wallMinAngle + && heldNormal.y > CeilingNormalThreshold) + { + probedNormal = heldNormal; + gap = heldGap; + } _wallNormal = probedNormal; _lostContactTimer = 0f; UpdateCeilingClass();