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; public int NewCount;
} }
#region RestaurantEvents #region RestaurantInteractionEvents
public class ItemSlotSelectedEvent : IEvent public class ItemSlotSelectedEvent : IEvent
{ {

View File

@ -1,4 +1,3 @@
using System.Collections.Generic;
using UnityEngine; using UnityEngine;
namespace DDD namespace DDD
@ -6,7 +5,7 @@ namespace DDD
public enum InteractionType public enum InteractionType
{ {
None, None,
RestaurantManagement, RestaurantManagementUi,
Count Count
} }
public interface IInteractable public interface IInteractable
@ -16,6 +15,7 @@ public interface IInteractable
InteractionType GetInteractionType(); InteractionType GetInteractionType();
GameObject GetInteractableGameObject(); GameObject GetInteractableGameObject();
void InitializeInteraction(InteractionType interactionType); void InitializeInteraction(InteractionType interactionType);
float GetRequiredHoldTime();
} }
public interface IInteractor public interface IInteractor
{ {
@ -24,6 +24,6 @@ public interface IInteractor
public interface IInteractionSolver 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, None = 0,
Move = 1 << 0, Move = 1 << 0,
Dash = 1 << 1, Dash = 1 << 1,
OpenManagementUi = 1 << 2, Interact = 1 << 2,
OpenManagementUi = 1 << 3,
} }
[Flags] [Flags]

View File

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

View File

@ -1,13 +1,65 @@
using DDD.RestaurantEvent; using System.Threading.Tasks;
using Sirenix.OdinInspector;
using UnityEngine; using UnityEngine;
using UnityEngine.InputSystem;
namespace DDD namespace DDD
{ {
public class RestaurantCharacterInteraction : MonoBehaviour, IInteractor, IEventHandler<RestaurantInteractionEvent> 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() 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) public void Invoke(RestaurantInteractionEvent evt)
@ -17,8 +69,54 @@ public void Invoke(RestaurantInteractionEvent evt)
public GameObject GetInteractorGameObject() public GameObject GetInteractorGameObject()
{ {
// TODO : TODO_IMPLEMENT_ME return gameObject;
return null; }
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 BoxCastExtentScale = 0.95f;
public float MinSlideFactorThreshold = 0.05f; public float MinSlideFactorThreshold = 0.05f;
public float InteractionRadius = 1f;
public LayerMask InteractionLayerMask;
// 디버그 // 디버그
public int InputLineSortingOrder = 10; public int InputLineSortingOrder = 10;
public int VelocityLineSortingOrder = 9; public int VelocityLineSortingOrder = 9;
@ -41,6 +44,7 @@ public class RestaurantPlayerDataSo : ScriptableObject
public InputAction MoveAction; public InputAction MoveAction;
public InputAction DashAction; public InputAction DashAction;
public InputAction InteractAction;
public InputAction OpenManagementUiAction; public InputAction OpenManagementUiAction;
} }
} }

View File

@ -1,4 +1,3 @@
using DDD.RestaurantEvent;
using Spine.Unity; using Spine.Unity;
using Unity.VisualScripting; using Unity.VisualScripting;
using UnityEngine; 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; using UnityEngine;
namespace DDD.RestaurantEvent namespace DDD
{ {
public class RestaurantInteractionComponent : MonoBehaviour, IInteractable public class RestaurantInteractionComponent : MonoBehaviour, IInteractable
{ {
[SerializeField] private InteractionType _interactionType = InteractionType.None;
[SerializeField] private float _holdTime = 1f;
public bool CanInteract() public bool CanInteract()
{ {
return true; return true;
@ -15,27 +18,29 @@ public bool OnInteracted(IInteractor interactor, ScriptableObject interactionPay
{ {
return false; return false;
} }
bool interactionResult = RestaurantInteractionEvents.RestaurantInteraction.RequestInteraction(interactor.GetInteractorGameObject(),
bool interactionResult = RestaurantEvents.RestaurantInteraction.RequestInteraction(interactor.GetInteractorGameObject(),
GetInteractableGameObject(), GetInteractionType(), interactionPayloadSo, true); GetInteractableGameObject(), GetInteractionType(), interactionPayloadSo, true);
return interactionResult; return interactionResult;
} }
public InteractionType GetInteractionType() public InteractionType GetInteractionType()
{ {
// TODO : TODO_IMPLEMENT_ME return _interactionType;
return InteractionType.None;
} }
public GameObject GetInteractableGameObject() public GameObject GetInteractableGameObject()
{ {
// TODO : TODO_IMPLEMENT_ME return gameObject;
return null;
} }
public void InitializeInteraction(InteractionType interactionType) 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 System.Collections.Generic;
using UnityEngine; using UnityEngine;
namespace DDD.RestaurantEvent namespace DDD
{ {
public static class RestaurantEvents public static class RestaurantInteractionEvents
{ {
public static RestaurantInteractionEvent RestaurantInteraction = new(); public static RestaurantInteractionEvent RestaurantInteraction = new();
} }
public static class RestaurantEventSolvers public static class RestaurantInteractionEventSolvers
{ {
public static Dictionary<InteractionType, Type> TypeToSolver = new() 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 GameObject Target;
public InteractionType InteractionType; public InteractionType InteractionType;
public ScriptableObject InteractionPayloadSo; public ScriptableObject InteractionPayloadSo;
public bool eventResult = false; public bool EventResult = false;
public RestaurantInteractionEvent MakeInteractionEvent(GameObject causer, GameObject target, InteractionType interactionType, public RestaurantInteractionEvent MakeInteractionEvent(GameObject causer, GameObject target, InteractionType interactionType,
ScriptableObject interactionPayloadSo) ScriptableObject interactionPayloadSo)
@ -41,18 +41,19 @@ public bool RequestInteraction(GameObject causer, GameObject target, Interaction
} }
var evt = MakeInteractionEvent(causer, target, interactionType, interactionPayloadSo); var evt = MakeInteractionEvent(causer, target, interactionType, interactionPayloadSo);
evt.eventResult = false; evt.EventResult = false;
// Solve event directly. 이벤트 처리는 여기서 하고, 이벤트 호출로는 이런 이벤트가 호출되었고 결과가 어떻다는 거 전파하는 식으로. // 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; IInteractionSolver solver = solverComponent as IInteractionSolver;
IInteractor interactor = causer.GetComponent<IInteractor>(); IInteractor interactor = causer.GetComponent<IInteractor>();
IInteractable interactable = target.GetComponent<IInteractable>();
// Cast solverComponent to IInteractable // Cast solverComponent to IInteractable
if (solver is not null && interactor is not null) if (solver is not null && interactor is not null)
{ {
evt.eventResult = solver.ExecuteInteraction(interactor, interactionPayloadSo); evt.EventResult = solver.ExecuteInteraction(interactor, interactable, interactionPayloadSo);
} }
else else
{ {
@ -62,7 +63,7 @@ public bool RequestInteraction(GameObject causer, GameObject target, Interaction
} }
EventBus.Broadcast(evt);// 이벤트 결과를 이거 받아서 처리하면 될듯. 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;
}
}
}