ProjectDDD/Assets/_DDD/_Scripts/RestaurantCharacter/RestaurantCharacterInteraction.cs

119 lines
4.1 KiB
C#
Raw Normal View History

2025-08-07 08:51:36 +00:00
using System.Collections.Generic;
using Sirenix.OdinInspector;
using UnityEngine;
namespace DDD
{
public class RestaurantCharacterInteraction : MonoBehaviour, IInteractor, IEventHandler<RestaurantInteractionEvent>
{
2025-08-06 08:43:41 +00:00
[SerializeField, ReadOnly] protected Collider[] _nearColliders = new Collider[10];
protected IInteractable _nearestInteractable;
protected IInteractable _previousInteractable;
protected IInteractable _interactingTarget;
protected float _interactHeldTime;
protected bool _isInteracting;
2025-08-06 08:43:41 +00:00
protected float _interactionRadius = 1f;
protected LayerMask _interactionLayerMask = (LayerMask)(-1);
2025-08-07 08:51:36 +00:00
private Dictionary<InteractionType, IInteractionSolver> _cachedSolvers = new();
2025-08-06 08:43:41 +00:00
protected virtual void Start() { }
2025-08-06 08:43:41 +00:00
protected virtual void Update()
{
_nearestInteractable = GetNearestInteractable();
2025-08-05 10:46:36 +00:00
if (_nearestInteractable != _previousInteractable)
{
_previousInteractable = _nearestInteractable;
2025-08-06 08:43:41 +00:00
OnNearestInteractableChanged(_nearestInteractable);
2025-08-05 10:46:36 +00:00
}
2025-08-06 08:43:41 +00:00
2025-08-05 10:46:36 +00:00
if (_isInteracting)
{
2025-08-05 10:46:36 +00:00
if (_nearestInteractable != _interactingTarget)
{
2025-08-06 08:43:41 +00:00
ResetInteractionState();
2025-08-05 10:46:36 +00:00
return;
}
_interactHeldTime += Time.deltaTime;
2025-08-05 10:46:36 +00:00
float requiredHoldTime = _interactingTarget.GetRequiredHoldTime();
float ratio = Mathf.Clamp01(_interactHeldTime / requiredHoldTime);
if (_interactHeldTime >= requiredHoldTime)
{
_isInteracting = false;
2025-08-05 10:46:36 +00:00
_interactingTarget.OnInteracted(this);
_interactingTarget = null;
2025-08-06 08:43:41 +00:00
OnInteractionCompleted();
}
2025-08-05 10:46:36 +00:00
2025-08-06 08:43:41 +00:00
OnInteractionHoldProgress(ratio);
}
}
2025-08-06 08:43:41 +00:00
protected virtual void OnDestroy() { }
2025-08-06 08:43:41 +00:00
protected virtual void OnNearestInteractableChanged(IInteractable newTarget) { }
protected virtual void OnInteractionHoldProgress(float ratio) { }
protected virtual void OnInteractionCompleted() { }
2025-08-06 08:43:41 +00:00
protected void ResetInteractionState()
{
_isInteracting = false;
2025-08-07 08:51:36 +00:00
_interactingTarget = null;
_interactHeldTime = 0f;
2025-08-06 08:43:41 +00:00
OnInteractionHoldProgress(0f);
}
2025-08-06 08:43:41 +00:00
protected IInteractable GetNearestInteractable()
{
2025-08-07 08:51:36 +00:00
int colliderCount = Physics.OverlapSphereNonAlloc(transform.position, _interactionRadius, _nearColliders, _interactionLayerMask);
float closestDistance = float.MaxValue;
IInteractable closest = null;
2025-08-07 08:51:36 +00:00
for (int i = 0; i < colliderCount; i++)
{
2025-08-07 08:51:36 +00:00
var col = _nearColliders[i];
if (col.TryGetComponent<IInteractable>(out var interactable) == false || interactable.CanInteract() == false) continue;
2025-08-06 08:43:41 +00:00
2025-08-07 08:51:36 +00:00
var type = interactable.GetInteractionType();
if (ContainTypeToSolver(type, out var solver) == false || solver.CanExecuteInteraction() == false) continue;
float distance = Vector3.Distance(transform.position, col.transform.position);
if (distance < closestDistance)
2025-08-06 08:43:41 +00:00
{
2025-08-07 08:51:36 +00:00
closestDistance = distance;
closest = interactable;
2025-08-06 08:43:41 +00:00
}
}
2025-08-06 08:43:41 +00:00
2025-08-07 08:51:36 +00:00
return closest;
2025-08-05 10:46:36 +00:00
}
2025-08-06 08:43:41 +00:00
public virtual void Invoke(RestaurantInteractionEvent evt) { }
public GameObject GetInteractorGameObject() => gameObject;
2025-08-07 08:51:36 +00:00
private bool ContainTypeToSolver(InteractionType type, out IInteractionSolver solver)
{
if (_cachedSolvers.TryGetValue(type, out solver)) return solver != null;
solver = null;
if (!RestaurantInteractionEventSolvers.TypeToSolver.TryGetValue(type, out var solverType)) return false;
if (!TryGetComponent(solverType, out var component)) return false;
solver = component as IInteractionSolver;
_cachedSolvers[type] = solver;
return solver != null;
}
}
2025-08-06 08:43:41 +00:00
}