Smooth free-camera flight and look

FreeCamController: ease movement via dt-correct Vector3.SmoothDamp on a world-space velocity (accel/decel ramp) and lag the look with Mathf.SmoothDampAngle. Both are framerate-independent and collapse to instant at smoothTime 0; smoothed state is snapped on activation (SyncToCurrentView) so entering freecam never jumps to catch up.

Bundles accumulated deferred work: PlayerScaler uniform-scale helper, scale-aware wall/ceiling climb probes and the double-scale skinned-collider bake fix, plus user content authoring (Sit pose + animation, font SDF, scene/prefab edits).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Opus 4.8 committed 2026-06-27 11:49:43 +02:00
1 parent f66ebbf10a
commit 8c89e95014
14 files changed
+12083 -360

No files matched your search

+46 -3
View File
@@ -39,6 +39,15 @@ public class FreeCamController : MonoBehaviour
[Range(1f, 89.9f)]
public float maxPitch = 89f;
[Header("Smoothing")]
[Tooltip("Acceleration/deceleration smoothing for flight, in seconds. 0 = instant (snappy starts/stops); higher = floatier ramp-up and coast-down.")]
[Range(0f, 1f)]
public float moveSmoothTime = 0.12f;
[Tooltip("Look smoothing, in seconds. 0 = raw mouse (instant); small values take the edge off jitter without feeling laggy.")]
[Range(0f, 0.3f)]
public float lookSmoothTime = 0.04f;
[Header("Camera")]
[Tooltip("Priority the dedicated CinemachineCamera takes while active (must beat the gameplay camera).")]
public int activePriority = 100;
@@ -48,8 +57,14 @@ public class FreeCamController : MonoBehaviour
CharacterController _controller;
CinemachineCamera _vcam;
float _yaw;
float _yaw; // look target (raw input accumulates here)
float _pitch;
float _displayYaw; // smoothed value actually applied to the transform
float _displayPitch;
float _yawSmoothRef;
float _pitchSmoothRef;
Vector3 _moveVelocity; // smoothed world-space flight velocity
Vector3 _moveVelocityRef;
bool _ignoredPlayer;
void Awake()
@@ -98,8 +113,21 @@ public class FreeCamController : MonoBehaviour
_yaw += delta.x * horizontalSensitivity;
float vs = verticalSensitivity * (invertY ? 1f : -1f);
_pitch = Mathf.Clamp(_pitch + delta.y * vs, -maxPitch, maxPitch);
if (lookSmoothTime > 0f)
{
// SmoothDampAngle is frame-rate-independent and wraps yaw correctly.
_displayYaw = Mathf.SmoothDampAngle(_displayYaw, _yaw, ref _yawSmoothRef, lookSmoothTime);
_displayPitch = Mathf.SmoothDampAngle(_displayPitch, _pitch, ref _pitchSmoothRef, lookSmoothTime);
}
else
{
_displayYaw = _yaw;
_displayPitch = _pitch;
}
// Rotation is unconstrained by the CharacterController; only position is.
transform.rotation = Quaternion.Euler(_pitch, _yaw, 0f);
transform.rotation = Quaternion.Euler(_displayPitch, _displayYaw, 0f);
}
void MoveTick()
@@ -109,7 +137,14 @@ public class FreeCamController : MonoBehaviour
dir.Normalize();
float speed = moveSpeed * (SprintHeld() ? sprintMultiplier : 1f);
_controller.Move(dir * (speed * Time.deltaTime));
Vector3 targetVelocity = dir * speed;
// SmoothDamp eases accel/decel and is already dt-correct; 0 collapses to instant.
_moveVelocity = moveSmoothTime > 0f
? Vector3.SmoothDamp(_moveVelocity, targetVelocity, ref _moveVelocityRef, moveSmoothTime)
: targetVelocity;
_controller.Move(_moveVelocity * Time.deltaTime);
}
/// <summary>Place the rig at the currently rendered view so going live produces no visible jump.</summary>
@@ -128,6 +163,14 @@ public class FreeCamController : MonoBehaviour
_yaw = e.y;
float p = e.x > 180f ? e.x - 360f : e.x;
_pitch = Mathf.Clamp(p, -maxPitch, maxPitch);
// Snap the smoothed state to the fresh pose so entering freecam never lags/jumps to catch up.
_displayYaw = _yaw;
_displayPitch = _pitch;
_yawSmoothRef = 0f;
_pitchSmoothRef = 0f;
_moveVelocity = Vector3.zero;
_moveVelocityRef = Vector3.zero;
}
/// <summary>Stop the freecam capsule from being blocked by the (frozen) player's capsule.</summary>