Ramp wall/ceiling climb movement for precise placement
Ramp the along-surface climb velocity via a gentle acceleration instead of snapping to full speed, so a brief tap nudges only a little. Sprint scales the accel so it stays snappy; releasing decelerates at the ground decel rate. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
9b9cc8fab8
commit
5c36ddc9e6
1 file changed
+24
-6
@@ -8,7 +8,7 @@ using UnityEngine.InputSystem;
|
||||
/// and jumping, sliding off too-steep slopes/edges, and a wall-climb mode.
|
||||
///
|
||||
/// Wall-climb (entered by pushing the move input into a wall): W/S climb straight up/down the
|
||||
/// wall at a constant speed, A/D strafe left/right relative to the camera, and the body always
|
||||
/// wall (velocity ramps in via a gentle acceleration for precise placement), A/D strafe left/right relative to the camera, and the body always
|
||||
/// faces the wall. Holding the left mouse button and dragging up/down leans the visual mesh out
|
||||
/// of or into the wall (only the model + its paint collider move; the capsule stays put, so the
|
||||
/// lean can sink into the wall); holding the right mouse button and dragging left/right turns the
|
||||
@@ -111,6 +111,11 @@ public class PlayerCharacterController : MonoBehaviour
|
||||
[Range(0f, 1f)]
|
||||
public float wallClimbSpeedMultiplier = 0.5f;
|
||||
|
||||
[Tooltip("How quickly wall/ceiling climb movement ramps up to speed (units/second²). Kept low so brief " +
|
||||
"taps nudge only a little for precise placement; scaled up while sprinting so sprint stays snappy.")]
|
||||
[Min(0.01f)]
|
||||
public float wallClimbAcceleration = 5f;
|
||||
|
||||
[Tooltip("Speed multiplier for the mantle (pulling up over the top edge), independent of the climb speed. Multiplies moveSpeed; 1 = full walk speed, >1 = snappier pull-up.")]
|
||||
[Min(0f)]
|
||||
public float wallMantleSpeedMultiplier = 1.5f;
|
||||
@@ -229,6 +234,7 @@ public class PlayerCharacterController : MonoBehaviour
|
||||
private NetworkPlayerSetup _setup; // sibling role source; null on non-networked test instances
|
||||
private float _verticalVelocity;
|
||||
private Vector3 _horizontalVelocity; // smoothed horizontal move velocity (accel/decel ramp)
|
||||
private Vector3 _climbVelocity; // smoothed along-surface climb velocity (accel ramp for precise placement)
|
||||
private bool _sprinting; // sprint key state this frame (exposed via IsSprinting)
|
||||
private bool _isIdle; // snapshot: player essentially still this frame (exposed via IsIdle)
|
||||
private bool _movingOnGround; // snapshot: grounded & moving above the run threshold (exposed via IsMovingOnGround)
|
||||
@@ -514,6 +520,7 @@ public class PlayerCharacterController : MonoBehaviour
|
||||
|
||||
_verticalVelocity = 0f;
|
||||
_horizontalVelocity = Vector3.zero;
|
||||
_climbVelocity = Vector3.zero;
|
||||
_slideSpeed = 0f;
|
||||
}
|
||||
|
||||
@@ -577,6 +584,7 @@ public class PlayerCharacterController : MonoBehaviour
|
||||
_wallStrafeSign = 0;
|
||||
_wallClimbSign = 0;
|
||||
_climbLeftGround = false;
|
||||
_climbVelocity = Vector3.zero; // start the climb ramp from rest
|
||||
}
|
||||
}
|
||||
|
||||
@@ -710,8 +718,8 @@ public class PlayerCharacterController : MonoBehaviour
|
||||
}
|
||||
else
|
||||
{
|
||||
// W/S climb straight up/down the wall at a constant speed (camera pitch never tilts
|
||||
// them). Strafe along the wall's own horizontal tangent, not the live camera-right
|
||||
// W/S climb straight up/down the wall (camera pitch never tilts them; speed ramps in
|
||||
// below). Strafe along the wall's own horizontal tangent, not the live camera-right
|
||||
// vector: feeding camera-right in here coupled movement to the orbit camera's
|
||||
// per-frame re-aim and jittered sideways motion. The camera only picks the sign.
|
||||
Vector3 wallUp = Vector3.ProjectOnPlane(Vector3.up, _wallNormal);
|
||||
@@ -791,9 +799,18 @@ public class PlayerCharacterController : MonoBehaviour
|
||||
|
||||
float climbSpeed = moveSpeed * wallClimbSpeedMultiplier;
|
||||
if (sprinting) climbSpeed *= sprintSpeedMultiplier;
|
||||
Vector3 velocity = Vector3.zero;
|
||||
if (alongSurface.sqrMagnitude > 1e-6f)
|
||||
velocity += alongSurface.normalized * climbSpeed;
|
||||
// Ramp the along-surface velocity instead of snapping to full speed: a gentle acceleration
|
||||
// lets a brief tap move you only a little, so you can place yourself precisely (especially
|
||||
// without sprint). Sprint scales the accel too, so it still reaches its higher speed quickly;
|
||||
// releasing decelerates at the ground decel rate for a prompt, controllable stop.
|
||||
Vector3 targetAlong = alongSurface.sqrMagnitude > 1e-6f
|
||||
? alongSurface.normalized * climbSpeed
|
||||
: Vector3.zero;
|
||||
float climbAccel = targetAlong.sqrMagnitude > 1e-6f
|
||||
? wallClimbAcceleration * (sprinting ? sprintSpeedMultiplier : 1f)
|
||||
: deceleration;
|
||||
_climbVelocity = Vector3.MoveTowards(_climbVelocity, targetAlong, climbAccel * dt);
|
||||
Vector3 velocity = _climbVelocity;
|
||||
if (found)
|
||||
{
|
||||
// Smoothly hold the capsule one skin-width off the surface (flush): the lean offset no
|
||||
@@ -1211,6 +1228,7 @@ public class PlayerCharacterController : MonoBehaviour
|
||||
_onCeiling = false;
|
||||
_lostContactTimer = 0f;
|
||||
_verticalVelocity = 0f;
|
||||
_climbVelocity = Vector3.zero;
|
||||
// Hand the current lean off to the residual so it eases home (EaseMeshOffsetToRest)
|
||||
// instead of snapping; latch the normal since the live one may shift after detaching.
|
||||
_meshOffsetResidual = _wallOffset;
|
||||
|
||||
Reference in new issue
Block a user