using UnityEngine; using UnityEngine.InputSystem; [DefaultExecutionOrder(1001)] public class CameraThirdPerson : MonoBehaviour { [System.Serializable] private class Settings { [Header("Sensivity")] [Tooltip("Camera follow smoothness (0 = instant, 1 = smooth)")] [Range(0, 1)] public float FollowSmoothness = .1f; [Tooltip("Camera rotation sensitivity")] public float LookSensitivity = 20f; [Header("Position")] [Tooltip("Camera distance from player")] public float Distance = 5; [Tooltip("Vertical offset from player")] public float VerticalOffset = 2; [Header("Pitch")] [Tooltip("Default pitch angle")] public float DefaultPitch = 20; [Tooltip("Min pitch angle")] public float MinPitch = -30; [Tooltip("Max pitch angle")] public float MaxPitch = 60; } [System.Serializable] public class References { public InputActionAsset InputActions; public Transform Target; } [SerializeField] private Settings _settings; [SerializeField] private References _references; private float _yaw; private float _pitch; private Vector3 _playerPosition; private InputAction _lookAction; void OnDrawGizmos() { Gizmos.color = Color.cyan; Gizmos.DrawWireCube(GetPlayerPosition(), Vector3.one * .2f); } void OnValidate() { _settings.DefaultPitch = Mathf.Clamp(_settings.DefaultPitch, _settings.MinPitch, _settings.MaxPitch); _pitch = _settings.DefaultPitch; _playerPosition = GetPlayerPosition(); SetPosition(); } void OnEnable() { _lookAction = _references.InputActions.FindActionMap("Player").FindAction("Look"); _lookAction?.Enable(); } void OnDisable() { _lookAction?.Disable(); } void Update() { float deltaTime = Time.deltaTime; _playerPosition = Vector3.Lerp(_playerPosition, GetPlayerPosition(), (1.1f - _settings.FollowSmoothness) * 20 * deltaTime); SetCursor(); SetYawAndPitch(deltaTime); SetPosition(); } private void SetCursor() { bool lockCursor = Player.Instance && !Player.Instance.State.IsPaused; Cursor.lockState = lockCursor ? CursorLockMode.Locked : CursorLockMode.None; Cursor.visible = !lockCursor; } private void SetYawAndPitch(float deltaTime) { if ((!Player.Instance || Player.Instance.State.IsPaused) && !_references.Target) return; Vector2 lookInput = _lookAction?.ReadValue() ?? Vector2.zero; _pitch -= lookInput.y * _settings.LookSensitivity * deltaTime; _pitch = Mathf.Clamp(_pitch, _settings.MinPitch, _settings.MaxPitch); _yaw += lookInput.x * _settings.LookSensitivity * deltaTime; } private void SetPosition() { // Relative postion between player and camera Vector3 cameraPosition = Vector3.forward * -_settings.Distance; // Rotate relative position with pitch and yaw cameraPosition = Quaternion.Euler(_pitch, _yaw, 0) * cameraPosition; // Convert relative player position to world position cameraPosition += _playerPosition; transform.position = cameraPosition; transform.rotation = Quaternion.LookRotation(_playerPosition - cameraPosition, Vector3.up); } private Vector3 GetPlayerPosition() { Vector3 offset = Vector3.up * _settings.VerticalOffset; if (_references.Target) return _references.Target.position + offset; else if(Player.Instance) return Player.Instance.transform.position + offset; return Vector3.zero + offset; } }