2025-08-07 08:51:36 +00:00
|
|
|
using System.Collections.Generic;
|
2025-08-05 08:09:14 +00:00
|
|
|
using Sirenix.OdinInspector;
|
2025-07-22 11:15:20 +00:00
|
|
|
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-05 08:09:14 +00:00
|
|
|
|
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-05 08:09:14 +00:00
|
|
|
|
2025-08-06 08:43:41 +00:00
|
|
|
protected virtual void Start() { }
|
2025-08-05 08:09:14 +00:00
|
|
|
|
2025-08-06 08:43:41 +00:00
|
|
|
protected virtual void Update()
|
|
|
|
{
|
2025-08-05 08:09:14 +00:00
|
|
|
_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 08:09:14 +00:00
|
|
|
{
|
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;
|
|
|
|
}
|
|
|
|
|
2025-08-05 08:09:14 +00:00
|
|
|
_interactHeldTime += Time.deltaTime;
|
|
|
|
|
2025-08-05 10:46:36 +00:00
|
|
|
float requiredHoldTime = _interactingTarget.GetRequiredHoldTime();
|
|
|
|
float ratio = Mathf.Clamp01(_interactHeldTime / requiredHoldTime);
|
|
|
|
|
|
|
|
if (_interactHeldTime >= requiredHoldTime)
|
2025-08-05 08:09:14 +00:00
|
|
|
{
|
|
|
|
_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 08:09:14 +00:00
|
|
|
}
|
2025-08-05 10:46:36 +00:00
|
|
|
|
2025-08-06 08:43:41 +00:00
|
|
|
OnInteractionHoldProgress(ratio);
|
2025-08-05 08:09:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-08-06 08:43:41 +00:00
|
|
|
protected virtual void OnDestroy() { }
|
2025-07-22 11:15:20 +00:00
|
|
|
|
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-05 08:09:14 +00:00
|
|
|
|
2025-08-06 08:43:41 +00:00
|
|
|
protected void ResetInteractionState()
|
2025-08-05 08:09:14 +00:00
|
|
|
{
|
|
|
|
_isInteracting = false;
|
2025-08-07 08:51:36 +00:00
|
|
|
_interactingTarget = null;
|
2025-08-05 08:09:14 +00:00
|
|
|
_interactHeldTime = 0f;
|
2025-08-06 08:43:41 +00:00
|
|
|
OnInteractionHoldProgress(0f);
|
2025-08-05 08:09:14 +00:00
|
|
|
}
|
|
|
|
|
2025-08-06 08:43:41 +00:00
|
|
|
protected IInteractable GetNearestInteractable()
|
2025-08-05 08:09:14 +00:00
|
|
|
{
|
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-05 08:09:14 +00:00
|
|
|
|
2025-08-07 08:51:36 +00:00
|
|
|
for (int i = 0; i < colliderCount; i++)
|
2025-08-05 08:09:14 +00:00
|
|
|
{
|
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-05 08:09:14 +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-07-22 11:15:20 +00:00
|
|
|
}
|
2025-08-06 08:43:41 +00:00
|
|
|
}
|