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-14 04:46:36 +00:00
|
|
|
if (_nearestInteractable != _interactingTarget || CanInteractTo(_interactingTarget) == false)
|
2025-08-05 10:46:36 +00:00
|
|
|
{
|
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
|
|
|
{
|
2025-08-13 09:31:34 +00:00
|
|
|
OnInteractionHoldProgress(1f);
|
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-12 11:46:30 +00:00
|
|
|
int colliderCount = Physics.OverlapSphereNonAlloc(transform.position, _interactionRadius, _nearColliders, _interactionLayerMask, QueryTriggerInteraction.Collide);
|
2025-08-07 08:51:36 +00:00
|
|
|
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];
|
2025-08-13 09:31:34 +00:00
|
|
|
if (col.TryGetComponent<IInteractable>(out var interactable) == false) continue;
|
2025-08-06 08:43:41 +00:00
|
|
|
|
2025-08-07 08:51:36 +00:00
|
|
|
var type = interactable.GetInteractionType();
|
2025-08-14 05:30:14 +00:00
|
|
|
if (interactable.IsInteractionHidden()) continue;
|
2025-08-14 04:46:36 +00:00
|
|
|
if (CanSolveInteractionType(type) == false) continue;
|
2025-08-07 08:51:36 +00:00
|
|
|
|
|
|
|
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-14 04:46:36 +00:00
|
|
|
|
|
|
|
public IInteractionSolver GetInteractionSolver(InteractionType interactionType)
|
|
|
|
{
|
|
|
|
TryGetSolverForType(interactionType, out var solver);
|
|
|
|
return solver;
|
|
|
|
}
|
|
|
|
|
|
|
|
public IInteractable GetFocusedInteractable()
|
|
|
|
{
|
|
|
|
return _nearestInteractable;
|
|
|
|
}
|
|
|
|
|
2025-08-13 09:31:34 +00:00
|
|
|
private bool TryGetSolverFor(IInteractable interactable, out IInteractionSolver solver)
|
|
|
|
{
|
|
|
|
solver = null;
|
|
|
|
if (interactable == null) return false;
|
|
|
|
|
|
|
|
return TryGetSolverForType(interactable.GetInteractionType(), out solver);
|
|
|
|
}
|
|
|
|
|
|
|
|
private bool TryGetSolverForType(InteractionType type, out IInteractionSolver solver)
|
2025-08-07 08:51:36 +00:00
|
|
|
{
|
|
|
|
if (_cachedSolvers.TryGetValue(type, out solver)) return solver != null;
|
|
|
|
|
|
|
|
solver = null;
|
|
|
|
|
2025-08-13 09:31:34 +00:00
|
|
|
if (RestaurantInteractionEventSolvers.TypeToSolver.TryGetValue(type, out var solverType) == false) return false;
|
2025-08-07 08:51:36 +00:00
|
|
|
|
2025-08-13 09:31:34 +00:00
|
|
|
if (transform.TryGetComponent(solverType, out var component) == false) return false;
|
2025-08-07 08:51:36 +00:00
|
|
|
|
|
|
|
solver = component as IInteractionSolver;
|
|
|
|
_cachedSolvers[type] = solver;
|
|
|
|
|
|
|
|
return solver != null;
|
|
|
|
}
|
2025-08-13 09:31:34 +00:00
|
|
|
|
2025-08-14 04:46:36 +00:00
|
|
|
public bool CanSolveInteractionType(InteractionType type)
|
2025-08-13 09:31:34 +00:00
|
|
|
{
|
|
|
|
if (_cachedSolvers.TryGetValue(type, out var cachedSolver)) return cachedSolver != null;
|
|
|
|
|
|
|
|
if (RestaurantInteractionEventSolvers.TypeToSolver.TryGetValue(type, out var solverType) == false) return false;
|
|
|
|
|
|
|
|
if (transform.TryGetComponent(solverType, out var component) == false) return false;
|
|
|
|
|
|
|
|
var solver = component as IInteractionSolver;
|
|
|
|
_cachedSolvers[type] = solver;
|
|
|
|
return solver != null;
|
|
|
|
}
|
|
|
|
|
2025-08-14 04:46:36 +00:00
|
|
|
public bool CanInteractTo(IInteractable interactable, ScriptableObject payloadSo = null)
|
2025-08-13 09:31:34 +00:00
|
|
|
{
|
|
|
|
if (interactable == null) return false;
|
|
|
|
if (interactable.CanInteract() == false) return false;
|
|
|
|
if (TryGetSolverFor(interactable, out var solver) == false) return false;
|
2025-08-14 04:46:36 +00:00
|
|
|
return solver.CanExecuteInteraction(this, interactable, payloadSo);
|
2025-08-13 09:31:34 +00:00
|
|
|
}
|
2025-07-22 11:15:20 +00:00
|
|
|
}
|
2025-08-06 08:43:41 +00:00
|
|
|
}
|