using UnityEngine; using UnityEngine.InputSystem; using Unheimlich.Data; using Unheimlich.Managers; namespace Unheimlich.Gameplay.Player { /// /// Handles camera effects: aim assist and shake. /// public class CameraEffects : MonoBehaviour { [Header("Settings")] public CameraEffectsSettings Settings; private float _shakeTimer = 0f; private float _shakeInterval; private Vector3 _shakeTarget; private Vector3 _shakeOriginalPos; private float _shakeSmoothness; private Vector3 _pendingAimAssistTarget; private bool _hasAimAssistTarget; public bool IsAimLocked { get; private set; } public bool HasActiveLookInput { get; private set; } public bool IsUsingGamepad { get; private set; } void Start() { if (Settings != null) _shakeInterval = 1f / Settings.shakeFrequency; } void Update() { DetectInputDevice(); } void LateUpdate() { if (_hasAimAssistTarget) { ApplyAimAssistInternal(_pendingAimAssistTarget); } } private void DetectInputDevice() { Vector2 lookInput = InputManager.GetLookInput(); HasActiveLookInput = lookInput.magnitude > 0.1f; if (Gamepad.current != null && Gamepad.current.rightStick.ReadValue().magnitude > 0.1f) IsUsingGamepad = true; else if (Mouse.current != null && Mouse.current.delta.ReadValue().magnitude > 0.1f) IsUsingGamepad = false; } public void ShakeCamera(float amplitude, float smoothness = 0f) { if (PlayerController.Instance == null || PlayerController.Instance.CameraPivot == null || Settings == null) return; _shakeSmoothness = smoothness; _shakeTimer -= Time.deltaTime; if (_shakeTimer <= 0f) { _shakeTimer = _shakeInterval * amplitude; _shakeOriginalPos = PlayerController.Instance.CameraPivot.position; float x = Random.Range(-1f, 1f) * amplitude; float y = Random.Range(-1f, 1f) * amplitude; _shakeTarget = _shakeOriginalPos + new Vector3(x, y, 0f); } if (_shakeSmoothness > 0f) { PlayerController.Instance.CameraPivot.position = Vector3.Lerp( PlayerController.Instance.CameraPivot.position, _shakeTarget, Time.deltaTime * _shakeSmoothness); } else { PlayerController.Instance.CameraPivot.position = _shakeTarget; } } public void ApplyAimAssist(Vector3 targetCenter) { _pendingAimAssistTarget = targetCenter; _hasAimAssistTarget = true; } private void ApplyAimAssistInternal(Vector3 targetCenter) { if (PlayerController.Instance == null || PlayerController.Instance.CameraTransform == null || Settings == null) return; if (PlayerController.Instance.Movement == null) return; if (IsAimLocked && HasActiveLookInput) IsAimLocked = false; Vector3 directionToTarget = (targetCenter - PlayerController.Instance.CameraTransform.position).normalized; float angleError = Vector3.Angle(PlayerController.Instance.CameraTransform.forward, directionToTarget); if (IsAimLocked || angleError < Settings.aimAssistMaxAngle) { Vector3 targetDirection = directionToTarget; float targetYaw = Mathf.Atan2(targetDirection.x, targetDirection.z) * Mathf.Rad2Deg; float targetPitch = -Mathf.Asin(targetDirection.y) * Mathf.Rad2Deg; float currentYaw = PlayerController.Instance.Movement.Yaw; float currentPitch = PlayerController.Instance.Movement.Pitch; float newYaw = Mathf.LerpAngle(currentYaw, targetYaw, Settings.aimAssistStrength * Time.deltaTime); float newPitch = Mathf.Lerp(currentPitch, targetPitch, Settings.aimAssistStrength * Time.deltaTime); PlayerController.Instance.Movement.Yaw = newYaw; PlayerController.Instance.Movement.Pitch = newPitch; } _hasAimAssistTarget = false; } public void LockAim(bool locked) { IsAimLocked = locked; } } }