ProjectDDD/Assets/_DDD/_Scripts/Restaurant/Character/Player/PlayerInteraction.cs

227 lines
8.0 KiB
C#
Raw Normal View History

using System;
using System.Collections.Generic;
2025-08-06 08:43:41 +00:00
using UnityEngine;
using UnityEngine.InputSystem;
namespace DDD.Restaurant
2025-08-06 08:43:41 +00:00
{
public class PlayerInteraction : CharacterInteraction
2025-08-06 08:43:41 +00:00
{
private RestaurantPlayerData _restaurantPlayerDataSo;
2025-08-06 08:43:41 +00:00
private float _interactHeldTime;
private bool _isInteracting;
private float _interactionStartTime = -1f;
2025-08-06 08:43:41 +00:00
protected override void Start()
{
base.Start();
2025-08-29 09:59:46 +00:00
Initialize();
2025-08-06 08:43:41 +00:00
}
2025-08-29 09:59:46 +00:00
private void Initialize()
2025-08-06 08:43:41 +00:00
{
2025-08-19 04:51:42 +00:00
_restaurantPlayerDataSo = RestaurantData.Instance.PlayerData;
2025-08-29 09:59:46 +00:00
_restaurantPlayerDataSo.InteractAction = InputManager.Instance.GetAction(InputActionMaps.Restaurant, nameof(RestaurantActions.Interact));
2025-08-06 08:43:41 +00:00
_restaurantPlayerDataSo.InteractAction.performed += OnInteractPerformed;
_restaurantPlayerDataSo.InteractAction.canceled += OnInteractCanceled;
_interactionRadius = _restaurantPlayerDataSo.InteractionRadius;
_interactionLayerMask = _restaurantPlayerDataSo.InteractionLayerMask;
EventBus.Register<RestaurantInteractionEvent>(this);
}
public override void InitializeSolvers()
{
var playerSolver = RestaurantInteractionEventSolvers.TypeToPlayerSolver;
Dictionary<InteractionType, Type> typesToSolver = new();
foreach (var typeToSolver in RestaurantInteractionEventSolvers.TypeToSolver)
{
typesToSolver.Add(typeToSolver.Key, typeToSolver.Value);
}
foreach (var typeToSolver in playerSolver)
{
typesToSolver[typeToSolver.Key] = typeToSolver.Value;
}
InitializeInteractionSolvers(typesToSolver);
}
2025-08-06 08:43:41 +00:00
protected override void OnDestroy()
{
base.OnDestroy();
if (_restaurantPlayerDataSo != null)
{
_restaurantPlayerDataSo.InteractAction.performed -= OnInteractPerformed;
_restaurantPlayerDataSo.InteractAction.canceled -= OnInteractCanceled;
}
EventBus.Unregister<RestaurantInteractionEvent>(this);
}
protected virtual void Update()
{
_nearestInteractable = GetNearestInteractable();
if (_nearestInteractable != _previousInteractable)
{
_previousInteractable = _nearestInteractable;
BroadcastInteractionUi(_nearestInteractable, CanInteractTo(_nearestInteractable), 0f);
}
if (_isInteracting)
{
if (_nearestInteractable != _interactingTarget || CanInteractTo(_interactingTarget) == false)
{
ResetInteractionState();
return;
}
_interactHeldTime += Time.deltaTime;
float requiredHoldTime = _interactingTarget.GetExecutionParameters().HoldTime;
float ratio = Mathf.Clamp01(_interactHeldTime / requiredHoldTime);
2025-08-27 08:05:54 +00:00
if (_interactHeldTime >= requiredHoldTime)
{
2025-08-27 08:05:54 +00:00
TryInteraction(_nearestInteractable);
OnInteractionCompleted();
ResetInteractionState();
BroadcastInteractionUi(_nearestInteractable, CanInteractTo(_nearestInteractable), 0f);
2025-08-27 08:05:54 +00:00
}
else
{
BroadcastInteractionUi(_nearestInteractable, CanInteractTo(_nearestInteractable), ratio);
}
}
else
{
BroadcastInteractionUi(_nearestInteractable, CanInteractTo(_nearestInteractable), 0f);
}
}
2025-08-06 08:43:41 +00:00
private void OnInteractPerformed(InputAction.CallbackContext context)
{
if (_nearestInteractable == null || CanInteractTo(_nearestInteractable) == false) return;
2025-08-06 08:43:41 +00:00
float requiredHoldTime = _nearestInteractable.GetExecutionParameters().HoldTime;
2025-08-06 08:43:41 +00:00
if (requiredHoldTime <= 0f)
{
2025-08-27 08:05:54 +00:00
TryInteraction(_nearestInteractable);
2025-08-06 08:43:41 +00:00
}
else
{
_isInteracting = true;
_interactHeldTime = 0f;
_interactingTarget = _nearestInteractable;
}
}
private void OnInteractCanceled(InputAction.CallbackContext context)
{
BroadcastInteractionUi(_nearestInteractable, CanInteractTo(_nearestInteractable), 0f);
2025-08-06 08:43:41 +00:00
ResetInteractionState();
_interactionStartTime = -1f;
2025-08-06 08:43:41 +00:00
}
protected override void OnInteractionCompleted()
2025-08-06 08:43:41 +00:00
{
2025-08-06 08:43:41 +00:00
}
private void BroadcastInteractionUi(IInteractable interactable, bool canInteract, float ratio)
2025-08-06 08:43:41 +00:00
{
if (interactable == null)
2025-08-06 08:43:41 +00:00
{
EventBus.Broadcast(GameEvents.HideInteractionUiEvent);
return;
2025-08-06 08:43:41 +00:00
}
2025-08-28 10:06:38 +00:00
var displayParameters = interactable.GetDisplayParameters();
2025-08-06 08:43:41 +00:00
var evt = GameEvents.ShowInteractionUiEvent;
evt.CanInteract = canInteract;
2025-08-28 10:06:38 +00:00
evt.TextKey = canInteract ? displayParameters.DefaultMessageKey : displayParameters.ConditionalMessageKey;
2025-08-06 08:43:41 +00:00
evt.HoldProgress = ratio;
EventBus.Broadcast(evt);
}
protected void ResetInteractionState()
{
_interactingTarget = null;
// Hold Progress
_isInteracting = false;
_interactingTarget = null;
_interactHeldTime = 0f;
BroadcastInteractionUi(_nearestInteractable, CanInteractTo(_nearestInteractable), 0f);
}
protected IInteractable GetNearestInteractable()
{
int colliderCount = Physics.OverlapSphereNonAlloc(transform.position, _interactionRadius, _nearColliders, _interactionLayerMask, QueryTriggerInteraction.Collide);
float closestDistance = float.MaxValue;
IInteractable closest = null;
for (int i = 0; i < colliderCount; i++)
{
var col = _nearColliders[i];
if (col.TryGetComponent<IInteractable>(out var interactable) == false) continue;
var type = interactable.GetInteractionType();
if (!interactable.IsInteractionAvailable()) continue;
if (CanSolveInteractionType(type) == false) continue;
if (IsInteractionHidden(interactable)) continue;
float distance = Vector3.Distance(transform.position, col.transform.position);
if (distance < closestDistance)
{
closestDistance = distance;
closest = interactable;
}
}
return closest;
}
2025-08-28 07:52:18 +00:00
public override bool FetchSolverTypeForInteraction(InteractionType type, out Type solverType)
2025-08-28 07:52:18 +00:00
{
if (RestaurantInteractionEventSolvers.TypeToPlayerSolver.TryGetValue(type, out solverType))
{
return true;
}
return base.FetchSolverTypeForInteraction(type, out solverType);
}
2025-09-02 06:49:34 +00:00
public override bool IsInteracting()
{
if (base.IsInteracting() == false) return false;
return _isInteracting;
}
public override float GetMovementSpeedMultiplier()
{
if (_isInteracting == false)
{
_interactionStartTime = -1f;
return 1f;
}
if (_interactionStartTime < 0f)
{
_interactionStartTime = Time.time;
}
float elapsed = Time.time - _interactionStartTime;
float normalizedTime = Mathf.Clamp01(elapsed / _restaurantPlayerDataSo.DecelerationTime);
return Mathf.Clamp01(_restaurantPlayerDataSo.InteractionDecelerationCurve.Evaluate(normalizedTime));
}
2025-08-06 08:43:41 +00:00
}
}