Smooth wall-climb lean-out offset to remove stepping

Replace the dead-beat-with-deadzone perpendicular controller with an
exponential follow that targets one skin-width beyond the offset, so the
capsule never penetrates the wall and the controller's depenetration no
longer fights back. Removes the quantizing deadzone that caused stepping.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Opus 4.8 committed 2026-06-22 19:43:23 +02:00
1 parent 27301f34d9
commit 534477f6f7
1 file changed
+10 -7
+10 -7
View File
@@ -92,6 +92,9 @@ public class PlayerCharacterController : MonoBehaviour
[Tooltip("How fast the lean-out offset eases back to the wall while moving (units/second).")]
public float wallOffsetReturnSpeed = 2f;
[Tooltip("How snappily the body follows the lean-out offset (1/second). Higher = tighter, lower = smoother.")]
public float wallOffsetFollow = 12f;
[Tooltip("Grace period (seconds) of lost contact tolerated before leaving wall-climb mode.")]
public float wallExitGrace = 0.15f;
@@ -406,14 +409,14 @@ public class PlayerCharacterController : MonoBehaviour
velocity += alongWall.normalized * climbSpeed;
if (found)
{
// Hold the chosen standoff (offset, 0 = flush) without fighting the controller's
// depenetration. A deadzone wider than the skin-width settling distance ignores
// sub-threshold gap noise that otherwise buzzed the body back and forth along the
// wall normal. Clamp guards against probe spikes.
// Smoothly approach the chosen standoff. Target one skin-width beyond the offset so
// the capsule rests just outside the surface (offset 0 = flush): the controller's
// depenetration never fights back, so there's no buzz and no quantizing deadzone is
// needed. Exponential follow keeps it framerate-stable; clamp guards probe spikes.
const float maxPerpSpeed = 8f;
float gapError = _wallOffset - gap;
if (Mathf.Abs(gapError) > _controller.skinWidth + 0.02f)
velocity += _wallNormal * Mathf.Clamp(gapError / dt, -maxPerpSpeed, maxPerpSpeed);
float gapError = (_wallOffset + _controller.skinWidth) - gap;
float follow = 1f - Mathf.Exp(-wallOffsetFollow * dt);
velocity += _wallNormal * Mathf.Clamp(gapError * follow / dt, -maxPerpSpeed, maxPerpSpeed);
}
_controller.Move(velocity * dt);