204 lines
6.5 KiB
C#
204 lines
6.5 KiB
C#
using UnityEngine;
|
|
using UnityEngine.EventSystems;
|
|
using UnityEngine.InputSystem;
|
|
using Cinemachine;
|
|
|
|
/// <summary>
|
|
/// Custom Cinemachine input handler that replaces CinemachineInputProvider.
|
|
/// Uses CinemachineCore.GetInputAxis delegate for total control over camera orbit.
|
|
///
|
|
/// Supports:
|
|
/// - Gamepad right stick (X = horizontal orbit, Y = vertical orbit)
|
|
/// - Mobile touch drag (right half of screen, ignoring UI)
|
|
/// - Mouse delta (desktop/editor)
|
|
///
|
|
/// Attach this to the CinemachineFreeLook camera GameObject.
|
|
/// Remove or disable CinemachineInputProvider if present.
|
|
/// </summary>
|
|
public class CinemachineCameraInput : MonoBehaviour
|
|
{
|
|
[Header("Sensitivity")]
|
|
[SerializeField] private float gamepadSensitivityX = 200f;
|
|
[SerializeField] private float gamepadSensitivityY = 3f;
|
|
[SerializeField] private float touchSensitivityX = 0.15f;
|
|
[SerializeField] private float touchSensitivityY = 0.003f;
|
|
[SerializeField] private float mouseSensitivityX = 3f;
|
|
[SerializeField] private float mouseSensitivityY = 0.03f;
|
|
|
|
[Header("Touch Settings")]
|
|
[Tooltip("Only process touches on the right portion of the screen (0.5 = right half)")]
|
|
[Range(0f, 1f)]
|
|
[SerializeField] private float touchActiveScreenRatio = 0.4f;
|
|
|
|
[Tooltip("Ignore touches over UI elements (buttons, joysticks, etc.)")]
|
|
[SerializeField] private bool ignoreUITouches = true;
|
|
|
|
[Header("Filtering")]
|
|
[SerializeField] private float stickDeadzone = 0.15f;
|
|
[SerializeField] private float smoothing = 0.1f;
|
|
|
|
// Touch tracking
|
|
private int activeTouchId = -1;
|
|
private Vector2 lastTouchPos;
|
|
|
|
// Smoothed output
|
|
private float smoothedX;
|
|
private float smoothedY;
|
|
private float rawX;
|
|
private float rawY;
|
|
|
|
// Axis names used by CinemachineFreeLook
|
|
private const string XAxisName = "Mouse X";
|
|
private const string YAxisName = "Mouse Y";
|
|
|
|
private CinemachineFreeLook freeLookCam;
|
|
|
|
private void Awake()
|
|
{
|
|
freeLookCam = GetComponent<CinemachineFreeLook>();
|
|
}
|
|
|
|
private void OnEnable()
|
|
{
|
|
// Override Cinemachine's input gathering with our custom handler
|
|
CinemachineCore.GetInputAxis = HandleCinemachineInput;
|
|
|
|
// Disable CinemachineInputProvider if present (we replace it)
|
|
var provider = GetComponent<CinemachineInputProvider>();
|
|
if (provider != null)
|
|
{
|
|
provider.enabled = false;
|
|
Debug.Log("[CinemachineCameraInput] Disabled CinemachineInputProvider — using custom input handler");
|
|
}
|
|
|
|
// Clear the default input axis names on the FreeLook camera
|
|
// This prevents Cinemachine from also reading legacy Input Manager axes
|
|
if (freeLookCam != null)
|
|
{
|
|
freeLookCam.m_XAxis.m_InputAxisName = "";
|
|
freeLookCam.m_YAxis.m_InputAxisName = "";
|
|
}
|
|
|
|
Debug.Log("[CinemachineCameraInput] Custom camera input enabled (gamepad + touch + mouse)");
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
// Restore default input handling when disabled
|
|
CinemachineCore.GetInputAxis = UnityEngine.Input.GetAxis;
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
// Gather raw input from all sources
|
|
rawX = 0f;
|
|
rawY = 0f;
|
|
|
|
ReadGamepadInput();
|
|
ReadTouchInput();
|
|
ReadMouseInput();
|
|
|
|
// Smooth the input
|
|
if (smoothing > 0.001f)
|
|
{
|
|
smoothedX = Mathf.Lerp(smoothedX, rawX, Time.unscaledDeltaTime / smoothing);
|
|
smoothedY = Mathf.Lerp(smoothedY, rawY, Time.unscaledDeltaTime / smoothing);
|
|
}
|
|
else
|
|
{
|
|
smoothedX = rawX;
|
|
smoothedY = rawY;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Delegate callback — Cinemachine calls this instead of Input.GetAxis
|
|
/// </summary>
|
|
private float HandleCinemachineInput(string axisName)
|
|
{
|
|
if (axisName == XAxisName) return smoothedX;
|
|
if (axisName == YAxisName) return smoothedY;
|
|
return 0f;
|
|
}
|
|
|
|
// ======================== GAMEPAD ========================
|
|
private void ReadGamepadInput()
|
|
{
|
|
if (Gamepad.current == null) return;
|
|
|
|
Vector2 rightStick = Gamepad.current.rightStick.ReadValue();
|
|
|
|
// Apply deadzone
|
|
if (rightStick.magnitude < stickDeadzone)
|
|
return;
|
|
|
|
rawX += rightStick.x * gamepadSensitivityX * Time.unscaledDeltaTime;
|
|
rawY += rightStick.y * gamepadSensitivityY * Time.unscaledDeltaTime;
|
|
}
|
|
|
|
// ======================== TOUCH ========================
|
|
private void ReadTouchInput()
|
|
{
|
|
if (Touchscreen.current == null) return;
|
|
|
|
var touches = Touchscreen.current.touches;
|
|
bool foundActiveTouch = false;
|
|
|
|
for (int i = 0; i < touches.Count; i++)
|
|
{
|
|
var touch = touches[i];
|
|
if (!touch.press.isPressed) continue;
|
|
|
|
int id = touch.touchId.ReadValue();
|
|
Vector2 pos = touch.position.ReadValue();
|
|
|
|
// If no active touch, try to start tracking this one
|
|
if (activeTouchId == -1)
|
|
{
|
|
// Only track touches on the right portion of the screen
|
|
if (pos.x < Screen.width * touchActiveScreenRatio)
|
|
continue;
|
|
|
|
// Ignore touches over UI elements
|
|
if (ignoreUITouches && EventSystem.current != null &&
|
|
EventSystem.current.IsPointerOverGameObject(id))
|
|
continue;
|
|
|
|
activeTouchId = id;
|
|
lastTouchPos = pos;
|
|
continue;
|
|
}
|
|
|
|
if (touch.touchId.ReadValue() != activeTouchId)
|
|
continue;
|
|
|
|
foundActiveTouch = true;
|
|
Vector2 delta = pos - lastTouchPos;
|
|
lastTouchPos = pos;
|
|
|
|
rawX += delta.x * touchSensitivityX;
|
|
rawY += delta.y * touchSensitivityY;
|
|
}
|
|
|
|
// Reset tracking if active touch released
|
|
if (activeTouchId != -1 && !foundActiveTouch)
|
|
{
|
|
activeTouchId = -1;
|
|
}
|
|
}
|
|
|
|
// ======================== MOUSE ========================
|
|
private void ReadMouseInput()
|
|
{
|
|
if (Mouse.current == null) return;
|
|
|
|
// Only use mouse if right button is held (prevents accidental camera rotation)
|
|
if (!Mouse.current.rightButton.isPressed) return;
|
|
|
|
Vector2 mouseDelta = Mouse.current.delta.ReadValue();
|
|
|
|
rawX += mouseDelta.x * mouseSensitivityX * Time.unscaledDeltaTime;
|
|
rawY += mouseDelta.y * mouseSensitivityY * Time.unscaledDeltaTime;
|
|
}
|
|
}
|