using Code.DI; using Code.Input; using UnityEngine; namespace Code.Gameplay.Camera { public class CameraController : MonoBehaviour { [SerializeField] private float rotationSpeed = 0.3f; [SerializeField] private float rotationSharpness = 50f; [SerializeField] private float followSharpness = 50f; [SerializeField] private float minVerticalAngle = -60f; [SerializeField] private float maxVerticalAngle = 60f; [SerializeField] private float defaultVerticalAngle; [SerializeField] private Transform followTransform; private UnityEngine.Camera _camera; private Vector3 _currentFollowPosition; private Vector3 _planarDirection; private float _targetVerticalAngle; private IInputService _inputService; private void Awake() { _camera = GetComponent(); if (!_camera) { enabled = false; return; } Initialize(); } private void Start() { _inputService = FindFirstObjectByType().Resolve(); } private void Initialize() { _targetVerticalAngle = Mathf.Clamp(defaultVerticalAngle, minVerticalAngle, maxVerticalAngle); _planarDirection = followTransform != null ? followTransform.forward : Vector3.forward; _currentFollowPosition = followTransform != null ? followTransform.position : Vector3.zero; } private void LateUpdate() { if (followTransform) { UpdateCamera(Time.deltaTime, GetLookInput()); } } private void UpdateCamera(float deltaTime, Vector3 lookInput) { HandleRotation(deltaTime, lookInput); HandlePosition(deltaTime); } private void HandleRotation(float deltaTime, Vector3 lookInput) { var horizontalRotation = Quaternion.Euler(Vector3.up * (lookInput.x * rotationSpeed)); _planarDirection = horizontalRotation * _planarDirection; var planarRotation = Quaternion.LookRotation(_planarDirection, followTransform.up); _targetVerticalAngle -= lookInput.y * rotationSpeed; _targetVerticalAngle = Mathf.Clamp(_targetVerticalAngle, minVerticalAngle, maxVerticalAngle); var verticalRotation = Quaternion.Euler(_targetVerticalAngle, 0, 0); var targetRotation = planarRotation * verticalRotation; transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, deltaTime * rotationSharpness); } private void HandlePosition(float deltaTime) { _currentFollowPosition = Vector3.Lerp( _currentFollowPosition, followTransform.position, 1f - Mathf.Exp(-followSharpness * deltaTime) ); transform.position = _currentFollowPosition; } private Vector3 GetLookInput() { return _inputService.LookInput; } public Quaternion GetCameraRotation() { return transform.rotation; } public Vector3 GetPlanarDirection() { return _planarDirection; } } }