Camera: smooth the walk look-ahead + pull default zoom in (feel)
The movement look-ahead added its 2.5u lead raw onto the framed point and smoothed only the final camera position, so the lead target snapped with the instantaneous input -- start/stop panned the view and reversing direction swung it ~5u (the jarring walk-shift). Fix with the genre-standard separate view-position technique: ease a dedicated _leadOffset toward the desired lead via a new gentle LeadSharpness knob, independent of FollowSharpness. Cut the lead magnitude 2.5->1.0 (AimLeadDistance, 0 = fully centred like Diablo/PoE) and pull the default zoom 16->13 (~19% closer). Code defaults + the live Game.unity Main Camera values both updated. See 2026-06-11_Camera_Feel_LookAhead_Zoom. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -63,7 +63,7 @@ namespace ProjectM.Client
|
||||
[Range(-180f, 180f)] public float Yaw = 0f;
|
||||
|
||||
[Header("Framing")]
|
||||
[Min(1f)] public float Distance = 16f;
|
||||
[Min(1f)] public float Distance = 13f;
|
||||
[Tooltip("Raise the look-at point off the ground toward the character's centre of mass.")]
|
||||
public float TargetHeight = 1f;
|
||||
|
||||
@@ -79,11 +79,16 @@ namespace ProjectM.Client
|
||||
public Vector3 FallbackTarget = new Vector3(3f, 0f, 4f);
|
||||
|
||||
[Header("Movement look-ahead")]
|
||||
[Tooltip("Shift the framed point this many world units toward where the player is aiming (0 = off). " +
|
||||
"Leads the camera toward the cursor / stick so aiming feels grounded. Smoothed by FollowSharpness.")]
|
||||
[Range(0f, 8f)] public float AimLeadDistance = 2.5f;
|
||||
[Tooltip("Lead the framed point this many world units toward the player's MOVEMENT direction " +
|
||||
"(0 = off, fully centred like Diablo / PoE). Kept subtle and eased in/out by LeadSharpness " +
|
||||
"so starting, stopping, or reversing glides instead of bumping the view.")]
|
||||
[Range(0f, 8f)] public float AimLeadDistance = 1f;
|
||||
[Tooltip("How fast the look-ahead offset eases toward its target (lower = smoother/slower). " +
|
||||
"Deliberately gentler than FollowSharpness so the lead glides instead of snapping with input.")]
|
||||
[Min(0f)] public float LeadSharpness = 3f;
|
||||
|
||||
Camera _cam;
|
||||
Vector3 _leadOffset; // smoothed look-ahead offset (world units), eased toward the desired lead each frame
|
||||
|
||||
void Awake() => _cam = GetComponent<Camera>();
|
||||
|
||||
@@ -102,14 +107,19 @@ namespace ProjectM.Client
|
||||
Vector3 target = HasTarget ? (Vector3)TargetWorldPos : FallbackTarget;
|
||||
target.y += TargetHeight;
|
||||
|
||||
// Movement look-ahead: lead the framed point toward where the player is MOVING (not aiming).
|
||||
// Leading toward AIM coupled the camera to the cursor: turning to face a near-cursor panned the cam,
|
||||
// which re-projected the live mouse ray -> the aim swam (worst near the player). Smoothed by FollowSharpness.
|
||||
// Movement look-ahead, smoothed INDEPENDENTLY of the follow. We lead toward MOVEMENT (not aim):
|
||||
// leading toward AIM coupled the cam to the cursor and made the aim swim. The desired lead snaps
|
||||
// with the raw input (full while held, zero when released); easing _leadOffset toward it at the
|
||||
// gentle LeadSharpness rate is what removes the "bump" - start / stop / reverse glide, never pan.
|
||||
Vector3 desiredLead = Vector3.zero;
|
||||
if (AimLeadDistance > 0f && HasTarget && math.lengthsq(TargetMoveDir) > 1e-6f)
|
||||
{
|
||||
float2 f = math.normalize(TargetMoveDir);
|
||||
target += new Vector3(f.x, 0f, f.y) * AimLeadDistance;
|
||||
desiredLead = new Vector3(f.x, 0f, f.y) * AimLeadDistance;
|
||||
}
|
||||
float leadK = LeadSharpness <= 0f ? 1f : 1f - Mathf.Exp(-LeadSharpness * Time.deltaTime);
|
||||
_leadOffset = Vector3.Lerp(_leadOffset, desiredLead, leadK);
|
||||
target += _leadOffset;
|
||||
|
||||
var rot = Quaternion.Euler(Pitch, Yaw, 0f);
|
||||
Vector3 desired = target - (rot * Vector3.forward) * Distance;
|
||||
|
||||
Reference in New Issue
Block a user