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

100 lines
3.4 KiB
C#
Raw Normal View History

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-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;
_interactHeldTime = 0f;
2025-08-06 08:43:41 +00:00
OnInteractionHoldProgress(0f);
2025-08-05 10:46:36 +00:00
_interactingTarget = null;
}
2025-08-06 08:43:41 +00:00
protected IInteractable GetNearestInteractable()
{
2025-08-06 08:43:41 +00:00
int nearColliderCount = Physics.OverlapSphereNonAlloc(transform.position, _interactionRadius,
_nearColliders, _interactionLayerMask, QueryTriggerInteraction.Collide);
2025-08-06 08:43:41 +00:00
IInteractable nearest = null;
float minSqrDistance = float.MaxValue;
for (int i = 0; i < nearColliderCount; i++)
{
var interactable = _nearColliders[i].GetComponent<IInteractable>();
2025-08-06 08:43:41 +00:00
if (interactable == null || !interactable.CanInteract()) continue;
float sqrDistance = (interactable.GetInteractableGameObject().transform.position - transform.position).sqrMagnitude;
if (sqrDistance < minSqrDistance)
{
minSqrDistance = sqrDistance;
nearest = interactable;
}
}
2025-08-06 08:43:41 +00:00
return nearest;
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-06 08:43:41 +00:00
}