DDD-76 상호작용 로직 수정 및 상호작용 오브젝트 테스트 완료

This commit is contained in:
NTG_Lenovo 2025-08-05 17:09:14 +09:00
parent ab7b77c9c8
commit f825d4f56b
11 changed files with 156 additions and 48 deletions

View File

@ -77,7 +77,7 @@ public class InventoryChangedEvent : IEvent
public int NewCount;
}
#region RestaurantEvents
#region RestaurantInteractionEvents
public class ItemSlotSelectedEvent : IEvent
{

View File

@ -1,4 +1,3 @@
using System.Collections.Generic;
using UnityEngine;
namespace DDD
@ -6,7 +5,7 @@ namespace DDD
public enum InteractionType
{
None,
RestaurantManagement,
RestaurantManagementUi,
Count
}
public interface IInteractable
@ -16,6 +15,7 @@ public interface IInteractable
InteractionType GetInteractionType();
GameObject GetInteractableGameObject();
void InitializeInteraction(InteractionType interactionType);
float GetRequiredHoldTime();
}
public interface IInteractor
{
@ -24,6 +24,6 @@ public interface IInteractor
public interface IInteractionSolver
{
bool ExecuteInteraction(IInteractor interactor, ScriptableObject interactionPayloadSo = null);
bool ExecuteInteraction(IInteractor interactor, IInteractable interactable, ScriptableObject interactionPayloadSo = null);
}
}

View File

@ -28,7 +28,8 @@ public enum RestaurantActions
None = 0,
Move = 1 << 0,
Dash = 1 << 1,
OpenManagementUi = 1 << 2,
Interact = 1 << 2,
OpenManagementUi = 1 << 3,
}
[Flags]

View File

@ -1,5 +1,3 @@
using DDD.RestaurantEvent;
using NUnit.Framework;
using UnityEngine;
namespace DDD
@ -8,13 +6,12 @@ public class RestaurantCharacter : MonoBehaviour, IGameCharacter, IInteractor
{
private void Start()
{
//TODO_IMPLEMENT_ME();
// TODO : Add event solvers dynamically
for (int i = (int)InteractionType.Count; i < (int)InteractionType.Count; i++)
for (int i = 0; i < (int)InteractionType.Count; i++)
{
InteractionType interactionType = (InteractionType)i;
// TODO : if this character should handle the interaction?
if(RestaurantEventSolvers.TypeToSolver.TryGetValue(interactionType, out var solverType))
if (RestaurantInteractionEventSolvers.TypeToSolver.TryGetValue(interactionType, out var solverType))
{
gameObject.AddComponent(solverType);
}
@ -23,8 +20,7 @@ private void Start()
public GameObject GetInteractorGameObject()
{
// TODO : TODO_IMPLEMENT_ME
return null;
return gameObject;
}
}
}

View File

@ -1,13 +1,65 @@
using DDD.RestaurantEvent;
using System.Threading.Tasks;
using Sirenix.OdinInspector;
using UnityEngine;
using UnityEngine.InputSystem;
namespace DDD
{
public class RestaurantCharacterInteraction : MonoBehaviour, IInteractor, IEventHandler<RestaurantInteractionEvent>
{
private RestaurantPlayerDataSo _restaurantPlayerDataSo;
[ReadOnly, SerializeField] private Collider[] _nearColliders = new Collider[10];
private IInteractable _nearestInteractable;
private float _interactHeldTime;
private bool _isInteracting;
private void Start()
{
EventBus.Register(this);
_ = Initialize();
}
private void Update()
{
if (!_restaurantPlayerDataSo) return;
_nearestInteractable = GetNearestInteractable();
if (_isInteracting && _nearestInteractable != null)
{
_interactHeldTime += Time.deltaTime;
if (_interactHeldTime >= _nearestInteractable.GetRequiredHoldTime())
{
_isInteracting = false;
_nearestInteractable.OnInteracted(this);
}
}
}
private void OnDestroy()
{
EventBus.Unregister<RestaurantInteractionEvent>(this);
if (_restaurantPlayerDataSo)
{
_restaurantPlayerDataSo.InteractAction.performed -= OnInteractPerformed;
_restaurantPlayerDataSo.InteractAction.canceled -= OnInteractCanceled;
}
}
private async Task Initialize()
{
_restaurantPlayerDataSo = await AssetManager.LoadAsset<RestaurantPlayerDataSo>(DataConstants.RestaurantPlayerDataSo);
Debug.Assert(_restaurantPlayerDataSo != null, "_restaurantPlayerDataSo is null");
_restaurantPlayerDataSo.InteractAction = InputManager.Instance.GetAction(InputActionMaps.Restaurant, nameof(RestaurantActions.Interact));
_restaurantPlayerDataSo.InteractAction.performed += OnInteractPerformed;
_restaurantPlayerDataSo.InteractAction.canceled += OnInteractCanceled;
EventBus.Register<RestaurantInteractionEvent>(this);
}
public void Invoke(RestaurantInteractionEvent evt)
@ -17,8 +69,54 @@ public void Invoke(RestaurantInteractionEvent evt)
public GameObject GetInteractorGameObject()
{
// TODO : TODO_IMPLEMENT_ME
return null;
return gameObject;
}
private void OnInteractPerformed(InputAction.CallbackContext context)
{
if (_nearestInteractable == null || _nearestInteractable.CanInteract() == false) return;
float requiredHoldTime = _nearestInteractable.GetRequiredHoldTime();
if (requiredHoldTime <= 0f)
{
_nearestInteractable.OnInteracted(this);
}
else
{
_isInteracting = true;
_interactHeldTime = 0f;
}
}
private void OnInteractCanceled(InputAction.CallbackContext context)
{
_isInteracting = false;
_interactHeldTime = 0f;
}
private IInteractable GetNearestInteractable()
{
int nearColliderCount = Physics.OverlapSphereNonAlloc(transform.position, _restaurantPlayerDataSo.InteractionRadius,
_nearColliders, _restaurantPlayerDataSo.InteractionLayerMask, QueryTriggerInteraction.Collide);
IInteractable nearestInteractable = null;
float minDistance = float.MaxValue;
for (int i = 0; i < nearColliderCount; i++)
{
var interactable = _nearColliders[i].GetComponent<IInteractable>();
if (interactable == null || interactable.CanInteract() == false) continue;
float sqrMagnitude = (interactable.GetInteractableGameObject().transform.position - transform.position).sqrMagnitude;
if (sqrMagnitude > minDistance) continue;
nearestInteractable = interactable;
minDistance = sqrMagnitude;
}
print(nearestInteractable?.GetInteractableGameObject().name);
return nearestInteractable;
}
}
}

View File

@ -28,6 +28,9 @@ public class RestaurantPlayerDataSo : ScriptableObject
public float BoxCastExtentScale = 0.95f;
public float MinSlideFactorThreshold = 0.05f;
public float InteractionRadius = 1f;
public LayerMask InteractionLayerMask;
// 디버그
public int InputLineSortingOrder = 10;
public int VelocityLineSortingOrder = 9;
@ -41,6 +44,7 @@ public class RestaurantPlayerDataSo : ScriptableObject
public InputAction MoveAction;
public InputAction DashAction;
public InputAction InteractAction;
public InputAction OpenManagementUiAction;
}
}

View File

@ -1,4 +1,3 @@
using DDD.RestaurantEvent;
using Spine.Unity;
using Unity.VisualScripting;
using UnityEngine;

View File

@ -1,13 +0,0 @@
using UnityEngine;
namespace DDD.RestaurantEvent
{
public class RestaurantManagementEventSolver : MonoBehaviour, IInteractionSolver
{
public bool ExecuteInteraction(IInteractor interactor, ScriptableObject interactionPayloadSo = null)
{
// TODO : TODO_IMPLEMENT_ME
return false;
}
}
}

View File

@ -1,9 +1,12 @@
using UnityEngine;
namespace DDD.RestaurantEvent
namespace DDD
{
public class RestaurantInteractionComponent : MonoBehaviour, IInteractable
{
[SerializeField] private InteractionType _interactionType = InteractionType.None;
[SerializeField] private float _holdTime = 1f;
public bool CanInteract()
{
return true;
@ -15,27 +18,29 @@ public bool OnInteracted(IInteractor interactor, ScriptableObject interactionPay
{
return false;
}
bool interactionResult = RestaurantEvents.RestaurantInteraction.RequestInteraction(interactor.GetInteractorGameObject(),
bool interactionResult = RestaurantInteractionEvents.RestaurantInteraction.RequestInteraction(interactor.GetInteractorGameObject(),
GetInteractableGameObject(), GetInteractionType(), interactionPayloadSo, true);
return interactionResult;
}
public InteractionType GetInteractionType()
{
// TODO : TODO_IMPLEMENT_ME
return InteractionType.None;
return _interactionType;
}
public GameObject GetInteractableGameObject()
{
// TODO : TODO_IMPLEMENT_ME
return null;
return gameObject;
}
public void InitializeInteraction(InteractionType interactionType)
{
// TODO : TODO_IMPLEMENT_ME
_interactionType = interactionType;
}
public float GetRequiredHoldTime()
{
return _holdTime;
}
}
}

View File

@ -2,18 +2,18 @@
using System.Collections.Generic;
using UnityEngine;
namespace DDD.RestaurantEvent
namespace DDD
{
public static class RestaurantEvents
public static class RestaurantInteractionEvents
{
public static RestaurantInteractionEvent RestaurantInteraction = new();
}
public static class RestaurantEventSolvers
public static class RestaurantInteractionEventSolvers
{
public static Dictionary<InteractionType, Type> TypeToSolver = new()
{
{InteractionType.RestaurantManagement, typeof(RestaurantManagementEventSolver)}
{InteractionType.RestaurantManagementUi, typeof(RestaurantManagementUiEventSolver)}
};
}
@ -23,7 +23,7 @@ public class RestaurantInteractionEvent : IEvent
public GameObject Target;
public InteractionType InteractionType;
public ScriptableObject InteractionPayloadSo;
public bool eventResult = false;
public bool EventResult = false;
public RestaurantInteractionEvent MakeInteractionEvent(GameObject causer, GameObject target, InteractionType interactionType,
ScriptableObject interactionPayloadSo)
@ -41,18 +41,19 @@ public bool RequestInteraction(GameObject causer, GameObject target, Interaction
}
var evt = MakeInteractionEvent(causer, target, interactionType, interactionPayloadSo);
evt.eventResult = false;
evt.EventResult = false;
// Solve event directly. 이벤트 처리는 여기서 하고, 이벤트 호출로는 이런 이벤트가 호출되었고 결과가 어떻다는 거 전파하는 식으로.
if (RestaurantEventSolvers.TypeToSolver.TryGetValue(interactionType, out var solverType))
if (RestaurantInteractionEventSolvers.TypeToSolver.TryGetValue(interactionType, out var solverType))
{
Component solverComponent = target.GetComponent(solverType);
Component solverComponent = causer.GetComponent(solverType);
IInteractionSolver solver = solverComponent as IInteractionSolver;
IInteractor interactor = causer.GetComponent<IInteractor>();
IInteractable interactable = target.GetComponent<IInteractable>();
// Cast solverComponent to IInteractable
if (solver is not null && interactor is not null)
{
evt.eventResult = solver.ExecuteInteraction(interactor, interactionPayloadSo);
evt.EventResult = solver.ExecuteInteraction(interactor, interactable, interactionPayloadSo);
}
else
{
@ -62,7 +63,7 @@ public bool RequestInteraction(GameObject causer, GameObject target, Interaction
}
EventBus.Broadcast(evt);// 이벤트 결과를 이거 받아서 처리하면 될듯.
return evt.eventResult;
return evt.EventResult;
}
}
}

View File

@ -0,0 +1,17 @@
using UnityEngine;
namespace DDD
{
public class RestaurantManagementUiEventSolver : MonoBehaviour, IInteractionSolver
{
public bool ExecuteInteraction(IInteractor interactor, IInteractable interactable, ScriptableObject interactionPayloadSo = null)
{
GameFlowState currentGameFlowState = GameFlowManager.Instance.GameFlowDataSo.CurrentGameState;
if (currentGameFlowState != GameFlowState.ReadyForRestaurant) return false;
var evt = GameEvents.OpenPopupUiEvent;
evt.UiType = typeof(RestaurantManagementUi);
EventBus.Broadcast(evt);
return true;
}
}
}