using UnityEngine; using Unheimlich.Interactions.Core; namespace Unheimlich.Gameplay.Player { /// /// Simulates camera head bobbing motion during player movement and idle states. /// Applies subtle oscillation based on player grounded and movement state. /// public class CameraHeadBob : MonoBehaviour { [Header("Bob Settings - Idle")] [SerializeField] private float _idleBobSpeed = 1f; [SerializeField] private float _idleBobAmplitude = 0.005f; [Header("Bob Settings - Walk")] [SerializeField] private float _walkBobSpeed = 12f; [SerializeField] private float _walkBobAmplitude = 0.02f; [SerializeField] private float _resetSpeed = 5f; private PlayerMovement _playerMovement; private float _timer = 0f; private Vector3 _startLocalPos; void Start() { _playerMovement = PlayerMovement.Instance; _startLocalPos = transform.localPosition; } void Update() { if (_playerMovement == null || _playerMovement.CharacterController == null) return; if (PlayerInspectionHandler.Instance != null && PlayerInspectionHandler.Instance.IsInspecting) { ApplyBob(_idleBobSpeed, _idleBobAmplitude); return; } bool isMoving = _playerMovement.IsMoving; bool isGrounded = _playerMovement.CharacterController.isGrounded; if (isGrounded) { if (isMoving) ApplyBob(_walkBobSpeed, _walkBobAmplitude); else ApplyBob(_idleBobSpeed, _idleBobAmplitude); } else ResetPosition(); } private void ApplyBob(float speed, float amplitude) { _timer += Time.deltaTime * speed; float x = Mathf.Sin(_timer * 0.5f) * amplitude; float y = Mathf.Cos(_timer) * amplitude; Vector3 newPos = _startLocalPos; newPos.x += x; newPos.y += y; transform.localPosition = newPos; } private void ResetPosition() { transform.localPosition = Vector3.Lerp(transform.localPosition, _startLocalPos, Time.deltaTime * _resetSpeed); if (Vector3.Distance(transform.localPosition, _startLocalPos) < 0.001f) _timer = 0f; } } }