public class CameraController : MonoBehaviour { private Camera _camera; private float _defaultFov; private float _currentFov; private float _currentTilt; [SerializeField] private float _fovChangeOnRun = 10f; [SerializeField] private float _fovLerpSpeed = 2f; [SerializeField] private float _fovLerpReturn = 10f; [SerializeField] private float _tiltLerpSpeed = 4f; [SerializeField] private float _tiltLerpReturn = 10f; [SerializeField] private float _tiltAmount = 1f; [SerializeField] float _bobSpeed = 14f; [SerializeField] float _bobAmount = 0.02f; private Vector2 _rawLookInput; private Vector2 _lookInputReady; [SerializeField] private float _horizSensitity; [SerializeField] private float _verticalSensitity; [SerializeField] private float _sensitivityMultiplierOnForwardRun = 0.6f; private float _xRotation; private float _yRotation; private float _maxVertLookDegree = 80; private void Start() { _camera = GetComponent(); _yRotation = transform.localRotation.eulerAngles.y; _defaultFov = _camera.fieldOfView; _currentFov = _camera.fieldOfView; Cursor.lockState = CursorLockMode.Locked; } private void Update() { var inputManager = FirstPersonCharacter.Instance.InputManager; _rawLookInput = inputManager.LookInput; _rawLookInput.x *= _horizSensitity; _rawLookInput.y *= _verticalSensitity; _lookInputReady = _rawLookInput; // Vertical look _xRotation -= _lookInputReady.y; _xRotation = Mathf.Clamp(_xRotation, -_maxVertLookDegree, _maxVertLookDegree); // Horizontal look _yRotation += inputManager.RunForward ? _lookInputReady.x * _sensitivityMultiplierOnForwardRun : _lookInputReady.x; float tilt = 0f; if (inputManager.MoveOblique && inputManager.Running && inputManager.MoveInput.x > 0) { tilt = _tiltAmount; } else if (inputManager.MoveOblique && inputManager.Running && inputManager.MoveInput.x < 0) { tilt = -_tiltAmount; } float tiltLerpSpeed = inputManager.MoveSideway ? _tiltLerpSpeed : _tiltLerpReturn; _currentTilt = Mathf.Lerp(_currentTilt, tilt, Time.deltaTime * tiltLerpSpeed); float lerpSpeed = inputManager.RunForward ? _fovLerpSpeed : _fovLerpReturn; float targetFov = inputManager.RunForward ? _defaultFov - _fovChangeOnRun : _defaultFov; _currentFov = Mathf.Lerp(_currentFov, targetFov, Time.deltaTime * lerpSpeed); _camera.fieldOfView = _currentFov; UpdateHeadBob(inputManager); FirstPersonCharacter.Instance.transform.localRotation = Quaternion.Euler(0f, _yRotation, 0f); transform.localRotation = Quaternion.Euler(_xRotation, _yRotation, _currentTilt); } private void UpdateHeadBob(PlayerInputManager inputManager) { if (inputManager.MoveInput != Vector2.zero) { float waveSlice = Mathf.Sin(Time.time * _bobSpeed); float totalBob = waveSlice * _bobAmount; transform.localPosition = new Vector3( transform.localPosition.x, FirstPersonCharacter.Instance.CamPositionTr.position.y + totalBob, transform.localPosition.z); } } }