Files
chameleon/Assets/Scripts/ThirdPersonOrbitInput.cs
T
adminandClaude Opus 4.8 f758c96dc5 Trim comments and use implicit null checks for Unity objects
Reduce comments to non-obvious "why" notes and convert UnityEngine.Object
null checks to implicit bool (if (obj) / if (!obj)). Input System devices
(Mouse.current, Keyboard.current) and plain arrays keep explicit != null.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 17:26:41 +02:00

181 lines
5.4 KiB
C#

using UnityEngine;
using Unity.Cinemachine;
#if ENABLE_INPUT_SYSTEM
using UnityEngine.InputSystem;
#endif
/// <summary>
/// Feeds mouse input into a <see cref="CinemachineOrbitalFollow"/> so the camera
/// orbits the follow target. Mouse movement drives yaw/pitch, the wheel zooms.
/// The orbit behaviour depends on <see cref="LookMode"/> (usually set by the
/// GameModeManager). Attach to the camera rig (the CinemachineOrbitalFollow).
/// </summary>
[RequireComponent(typeof(CinemachineOrbitalFollow))]
[DisallowMultipleComponent]
public class ThirdPersonOrbitInput : MonoBehaviour
{
public enum OrbitLookMode
{
/// <summary>Rotate with every mouse move; cursor locked/hidden.</summary>
AlwaysActive,
/// <summary>Rotate only while the right mouse button is held; cursor free otherwise.</summary>
HoldRightMouseButton,
/// <summary>No rotation; cursor free.</summary>
Disabled
}
[Header("Look Mode")]
[Tooltip("How the camera orbit is driven (usually set by GameModeManager).")]
[SerializeField] private OrbitLookMode lookMode = OrbitLookMode.AlwaysActive;
[Header("Rotation")]
[Tooltip("Horizontal look sensitivity (degrees of yaw per pixel).")]
public float horizontalSensitivity = 0.2f;
[Tooltip("Vertical look sensitivity (degrees of pitch per pixel).")]
public float verticalSensitivity = 0.15f;
[Tooltip("Invert vertical look (mouse up tilts the camera down).")]
public bool invertY = false;
[Header("Zoom")]
[Tooltip("Mouse wheel zooms the camera in and out (changes orbit radius).")]
public bool enableZoom = true;
[Tooltip("World units the orbit radius changes per mouse wheel notch.")]
public float zoomSpeed = 0.5f;
[Tooltip("Closest orbit radius (zoom in).")]
public float minRadius = 1.5f;
[Tooltip("Farthest orbit radius (zoom out).")]
public float maxRadius = 8f;
[Header("Cursor")]
[Tooltip("Lock and hide the cursor while the camera is actively rotating.")]
public bool manageCursor = true;
CinemachineOrbitalFollow _orbit;
/// <summary>Current orbit mode. Setting it also refreshes the cursor state.</summary>
public OrbitLookMode LookMode
{
get => lookMode;
set { lookMode = value; ApplyCursorState(); }
}
void Awake()
{
_orbit = GetComponent<CinemachineOrbitalFollow>();
if (!_orbit)
Debug.LogError("[ThirdPersonOrbitInput] No CinemachineOrbitalFollow found on this GameObject.", this);
}
void OnEnable() => ApplyCursorState();
void OnDisable() => SetCursorLocked(false);
void Update()
{
if (!_orbit)
return;
bool rotating = ShouldRotate();
if (manageCursor)
SetCursorLocked(rotating);
if (rotating)
{
Vector2 delta = ReadMouseDelta();
if (delta.sqrMagnitude > 0f)
{
ApplyAxisDelta(ref _orbit.HorizontalAxis, delta.x * horizontalSensitivity);
float pitch = delta.y * verticalSensitivity * (invertY ? 1f : -1f);
ApplyAxisDelta(ref _orbit.VerticalAxis, pitch);
}
}
if (enableZoom)
{
float scroll = ReadScroll();
if (!Mathf.Approximately(scroll, 0f))
{
// One wheel notch = one zoom step (sign only), independent of the
// platform's raw wheel magnitude. Scrolling up zooms in.
_orbit.Radius = Mathf.Clamp(_orbit.Radius - Mathf.Sign(scroll) * zoomSpeed, minRadius, maxRadius);
}
}
}
bool ShouldRotate()
{
switch (lookMode)
{
case OrbitLookMode.AlwaysActive: return true;
case OrbitLookMode.HoldRightMouseButton: return IsRightMouseHeld();
default: return false;
}
}
void ApplyCursorState()
{
if (manageCursor)
SetCursorLocked(ShouldRotate());
}
/// <summary>Adds to an input axis; wrapping axes wrap, others clamp to their range.</summary>
static void ApplyAxisDelta(ref InputAxis axis, float amount)
{
float value = axis.Value + amount;
float min = axis.Range.x;
float max = axis.Range.y;
if (axis.Wrap && max > min)
{
float span = max - min;
value = ((value - min) % span + span) % span + min;
}
else
{
value = Mathf.Clamp(value, min, max);
}
axis.Value = value;
}
static void SetCursorLocked(bool locked)
{
Cursor.lockState = locked ? CursorLockMode.Locked : CursorLockMode.None;
Cursor.visible = !locked;
}
bool IsRightMouseHeld()
{
#if ENABLE_INPUT_SYSTEM
return Mouse.current != null && Mouse.current.rightButton.isPressed;
#else
return Input.GetMouseButton(1);
#endif
}
Vector2 ReadMouseDelta()
{
#if ENABLE_INPUT_SYSTEM
return Mouse.current != null ? Mouse.current.delta.ReadValue() : Vector2.zero;
#else
return new Vector2(Input.GetAxisRaw("Mouse X"), Input.GetAxisRaw("Mouse Y")) * 10f;
#endif
}
float ReadScroll()
{
#if ENABLE_INPUT_SYSTEM
// Raw wheel delta; only its sign is used (one notch = one zoom step).
return Mouse.current != null ? Mouse.current.scroll.ReadValue().y : 0f;
#else
return Input.GetAxis("Mouse ScrollWheel");
#endif
}
}