100 lines
3.4 KiB
C#
100 lines
3.4 KiB
C#
using Sirenix.OdinInspector;
|
|
using UnityEngine;
|
|
|
|
namespace DDD
|
|
{
|
|
public class RestaurantCharacterInteraction : MonoBehaviour, IInteractor, IEventHandler<RestaurantInteractionEvent>
|
|
{
|
|
[SerializeField, ReadOnly] protected Collider[] _nearColliders = new Collider[10];
|
|
|
|
protected IInteractable _nearestInteractable;
|
|
protected IInteractable _previousInteractable;
|
|
protected IInteractable _interactingTarget;
|
|
|
|
protected float _interactHeldTime;
|
|
protected bool _isInteracting;
|
|
|
|
protected float _interactionRadius = 1f;
|
|
protected LayerMask _interactionLayerMask = (LayerMask)(-1);
|
|
|
|
protected virtual void Start() { }
|
|
|
|
protected virtual void Update()
|
|
{
|
|
_nearestInteractable = GetNearestInteractable();
|
|
|
|
if (_nearestInteractable != _previousInteractable)
|
|
{
|
|
_previousInteractable = _nearestInteractable;
|
|
OnNearestInteractableChanged(_nearestInteractable);
|
|
}
|
|
|
|
if (_isInteracting)
|
|
{
|
|
if (_nearestInteractable != _interactingTarget)
|
|
{
|
|
ResetInteractionState();
|
|
return;
|
|
}
|
|
|
|
_interactHeldTime += Time.deltaTime;
|
|
|
|
float requiredHoldTime = _interactingTarget.GetRequiredHoldTime();
|
|
float ratio = Mathf.Clamp01(_interactHeldTime / requiredHoldTime);
|
|
|
|
if (_interactHeldTime >= requiredHoldTime)
|
|
{
|
|
_isInteracting = false;
|
|
_interactingTarget.OnInteracted(this);
|
|
_interactingTarget = null;
|
|
OnInteractionCompleted();
|
|
}
|
|
|
|
OnInteractionHoldProgress(ratio);
|
|
}
|
|
}
|
|
|
|
protected virtual void OnDestroy() { }
|
|
|
|
protected virtual void OnNearestInteractableChanged(IInteractable newTarget) { }
|
|
protected virtual void OnInteractionHoldProgress(float ratio) { }
|
|
protected virtual void OnInteractionCompleted() { }
|
|
|
|
protected void ResetInteractionState()
|
|
{
|
|
_isInteracting = false;
|
|
_interactHeldTime = 0f;
|
|
OnInteractionHoldProgress(0f);
|
|
_interactingTarget = null;
|
|
}
|
|
|
|
protected IInteractable GetNearestInteractable()
|
|
{
|
|
int nearColliderCount = Physics.OverlapSphereNonAlloc(transform.position, _interactionRadius,
|
|
_nearColliders, _interactionLayerMask, QueryTriggerInteraction.Collide);
|
|
|
|
IInteractable nearest = null;
|
|
float minSqrDistance = float.MaxValue;
|
|
|
|
for (int i = 0; i < nearColliderCount; i++)
|
|
{
|
|
var interactable = _nearColliders[i].GetComponent<IInteractable>();
|
|
if (interactable == null || !interactable.CanInteract()) continue;
|
|
|
|
float sqrDistance = (interactable.GetInteractableGameObject().transform.position - transform.position).sqrMagnitude;
|
|
if (sqrDistance < minSqrDistance)
|
|
{
|
|
minSqrDistance = sqrDistance;
|
|
nearest = interactable;
|
|
}
|
|
}
|
|
|
|
return nearest;
|
|
}
|
|
|
|
public virtual void Invoke(RestaurantInteractionEvent evt) { }
|
|
|
|
public GameObject GetInteractorGameObject() => gameObject;
|
|
}
|
|
}
|