Files
Ipseity-Demo/Assets/Unheimlich_POC/Scripts/Gameplay/GameObjects/Player/CameraHeadBob.cs
T

142 lines
4.1 KiB
C#

using UnityEngine;
using Unheimlich.Interactions.Core;
using Unheimlich.Data.CameraSettings;
namespace Unheimlich.Gameplay.Player
{
/// <summary>
/// Simulates camera head bobbing motion during player movement and idle states.
/// Applies subtle oscillation based on player grounded and movement state.
/// </summary>
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;
private HeadBobMode _overrideMode = HeadBobMode.Normal;
private bool _hasOverride = false;
private Coroutine _resetCoroutine;
void Start()
{
_playerMovement = PlayerMovement.Instance;
_startLocalPos = transform.localPosition;
}
void Update()
{
if (_playerMovement == null || _playerMovement.CharacterController == null)
return;
HeadBobMode currentMode = _hasOverride ? _overrideMode : HeadBobMode.Normal;
if (currentMode == HeadBobMode.Disabled)
{
ResetPosition();
return;
}
if (currentMode == HeadBobMode.Idle || (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();
}
/// <summary>
/// Sets the head bob mode override.
/// </summary>
public void SetMode(HeadBobMode mode)
{
_overrideMode = mode;
_hasOverride = true;
}
/// <summary>
/// Clears the override and returns to normal behavior.
/// </summary>
public void ClearOverride()
{
_hasOverride = false;
if (_resetCoroutine != null)
{
StopCoroutine(_resetCoroutine);
_resetCoroutine = null;
}
}
/// <summary>
/// Smoothly lerps the head bob position to zero over the specified duration.
/// </summary>
public void LerpToZero(float duration)
{
if (_resetCoroutine != null)
StopCoroutine(_resetCoroutine);
_resetCoroutine = StartCoroutine(LerpToZeroCoroutine(duration));
}
private System.Collections.IEnumerator LerpToZeroCoroutine(float duration)
{
Vector3 startPos = transform.localPosition;
float elapsed = 0f;
while (elapsed < duration)
{
elapsed += Time.deltaTime;
float t = Mathf.Clamp01(elapsed / duration);
transform.localPosition = Vector3.Lerp(startPos, Vector3.zero, t);
yield return null;
}
transform.localPosition = Vector3.zero;
_resetCoroutine = null;
}
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;
}
}
}