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);
}
}
}