Carry first-person facing into orbit camera on mode switch

When leaving first person for an orbit mode (Paint / Player Control), snap
the orbit axes to Camera.main's current view direction instead of restoring
the orbit's last-used angle. With WorldSpace binding + Sphere orbit + a
centered composer the camera look rotation is exactly
Euler(VerticalAxis, HorizontalAxis, 0), so the inverse mapping is exact.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Opus 4.8 committed 2026-06-28 23:02:31 +02:00
1 parent 054cadbd80
commit a7a4fbdcb7
2 files changed
+31 -1

No files matched your search

+6
View File
@@ -36,6 +36,12 @@ public class FirstPersonMode : GameMode
Manager.FirstPerson.SetActive(false);
if (Manager.CameraInput)
{
Manager.CameraInput.enabled = true;
// Carry the first-person facing into the orbit camera so the next orbit mode (Paint / Player
// Control) keeps the current view angle instead of snapping back to the orbit's last-used angle.
// Camera.main still shows the first-person view this frame (the brain hasn't blended yet).
Manager.CameraInput.SyncToView();
}
}
}
+25 -1
View File
@@ -123,6 +123,27 @@ public class ThirdPersonOrbitInput : MonoBehaviour
_zoomInit = true;
}
/// <summary>Snaps the orbit axes so the camera faces along Camera.main's current view direction, so the
/// next orbit mode keeps that facing instead of restoring the orbit's last-used angle. Called when
/// switching out of a non-orbit rig (first person): Camera.main still shows that rig's view this frame
/// (the brain hasn't blended yet), so the read is exact. With WorldSpace binding + Sphere orbit + a
/// centered composer the camera look rotation is exactly Euler(VerticalAxis, HorizontalAxis, 0), so
/// HorizontalAxis = world yaw and VerticalAxis = world pitch (positive = looking down). No-op without a
/// live camera/orbit.</summary>
public void SyncToView()
{
if (!_orbit) return;
var cam = Camera.main;
if (!cam) return;
Vector3 e = cam.transform.rotation.eulerAngles;
SetAxisValue(ref _orbit.HorizontalAxis, e.y > 180f ? e.y - 360f : e.y);
SetAxisValue(ref _orbit.VerticalAxis, e.x > 180f ? e.x - 360f : e.x);
// Drop any eased look carry-over so the snapped angle isn't immediately dragged back.
_smoothedLook = Vector2.zero;
}
void Update()
{
if (!_orbit)
@@ -210,8 +231,11 @@ public class ThirdPersonOrbitInput : MonoBehaviour
/// <summary>Adds to an input axis; wrapping axes wrap, others clamp to their range.</summary>
static void ApplyAxisDelta(ref InputAxis axis, float amount)
=> SetAxisValue(ref axis, axis.Value + amount);
/// <summary>Sets an input axis to an absolute value; wrapping axes wrap, others clamp to their range.</summary>
static void SetAxisValue(ref InputAxis axis, float value)
{
float value = axis.Value + amount;
float min = axis.Range.x;
float max = axis.Range.y;