using ActionRPG.Input; using ActionRPG.Interfaces; using UnityEngine; using static ActionRPG.Interfaces.InteractionType; namespace ActionRPG.Interaction { /// /// Casts a ray from the player's camera each frame to detect IInteractable objects. /// Subscribes to PlayerInputReader to trigger interaction on the correct input. /// [RequireComponent(typeof(PlayerInputReader))] public class PlayerInteractor : MonoBehaviour { [Header("Raycast")] [SerializeField] private Camera _camera; [SerializeField, Min(0f)] private float _interactRange = 2.5f; [SerializeField] private LayerMask _interactableLayer; private PlayerInputReader _input; private IInteractable _currentTarget; private void Awake() { _input = GetComponent(); if (_camera == null) _camera = Camera.main; } private void OnEnable() { _input.OnInteractStarted += HandleInteractPress; _input.OnInteractPerformed += HandleInteractHold; } private void OnDisable() { _input.OnInteractStarted -= HandleInteractPress; _input.OnInteractPerformed -= HandleInteractHold; ClearTarget(); } private void Update() { Ray ray = new Ray(_camera.transform.position, _camera.transform.forward); if (Physics.Raycast(ray, out RaycastHit hit, _interactRange, _interactableLayer)) { IInteractable target = hit.collider.GetComponentInParent(); if (target != null && target != _currentTarget) { ClearTarget(); _currentTarget = target; _currentTarget.OnFocused(); } } else { ClearTarget(); } } private void HandleInteractPress() { if (_currentTarget?.InteractionType == InteractionType.Press) _currentTarget.Interact(); } private void HandleInteractHold() { if (_currentTarget?.InteractionType == InteractionType.Hold) _currentTarget.Interact(); } private void ClearTarget() { if (_currentTarget == null) return; _currentTarget.OnLostFocus(); _currentTarget = null; } private void OnDrawGizmosSelected() { if (_camera == null) return; Gizmos.color = _currentTarget != null ? Color.green : Color.yellow; Gizmos.DrawRay(_camera.transform.position, _camera.transform.forward * _interactRange); } } }