레스토랑 오더 상호작용 서브시스템 도입 및 주문/서빙 솔버 추가, 관련 상호작용/캐릭터 로직 갱신

This commit is contained in:
Jeonghyeon Ha 2025-08-20 16:50:29 +09:00
parent 4c7d9c17e6
commit a28415330c
15 changed files with 245 additions and 116 deletions

View File

@ -3,11 +3,22 @@
namespace DDD
{
public interface IInteractionSubsystemObject<T> where T : Enum
public interface IInteractionSubsystemObject
{
Type GetSubsystemEnumType();
void InitializeSubsystem();
bool CanInteract();
bool OnInteracted(IInteractor interactor, ScriptableObject payloadSo = null);
}
public interface IInteractionSubsystemObject<T> : IInteractionSubsystemObject where T : Enum
{
T GetInteractionSubsystemType();
}
public interface IInteractionSubsystemSolver<T> where T : Enum
public interface IInteractionSubsystemSolver
{
}
public interface IInteractionSubsystemSolver<T> : IInteractionSubsystemSolver where T : Enum
{
bool ExecuteInteractionSubsystem(IInteractor interactor, IInteractable interactable, ScriptableObject payloadSo = null);
bool CanExecuteInteractionSubsystem(IInteractor interactor = null, IInteractable interactable = null,

View File

@ -23,7 +23,7 @@ protected virtual void Start()
var flag = typeToSolver.Key;
if (flag == InteractionType.None) continue;
if ((_interactionComponent.InteractionType & flag) == 0) continue;
if ((_interactionComponent.AvailableInteractions & flag) == 0) continue;
if (!TryGetComponent(typeToSolver.Value, out _))
{

View File

@ -6,10 +6,10 @@ namespace DDD
{
public class RestaurantCharacterInteraction : MonoBehaviour, IInteractor, IEventHandler<RestaurantInteractionEvent>
{
[EnumToggleButtons, SerializeField] protected InteractionType _interactionType;
[EnumToggleButtons, SerializeField] protected InteractionType _availableInteractions;
[SerializeField, ReadOnly] protected Collider[] _nearColliders = new Collider[10];
public InteractionType InteractionType => _interactionType;
public InteractionType AvailableInteractions => _availableInteractions;
protected IInteractable _nearestInteractable;
protected IInteractable _previousInteractable;

View File

@ -1,79 +0,0 @@
using System;
using UnityEngine;
namespace DDD
{
[Flags]
public enum RestaurantOrderInteractionType : uint
{
// None = 0u,
WaitCustomer = 0,
// WaitCustomer = 1u << 0,
// WaitOrder = 1u << 1,
// WaitServe = 1u << 2,
// All = 0xFFFFFFFFu
}
public class RestaurantOrderInteraction : RestaurantInteractionComponent, IInteractionSubsystemObject<RestaurantOrderInteractionType>
{
[SerializeField] protected RestaurantOrderInteractionType _initialOrderInteractionType = RestaurantOrderInteractionType.WaitCustomer;
private RestaurantOrderInteractionType _currentRestaurantOrderInteractionType;
// EDITOR
private void Reset()
{
SetInteractionTypeToRestaurantOrder();
}
private void OnValidate()
{
SetInteractionTypeToRestaurantOrder();
}
// ~EDITOR
private void Start()
{
_currentRestaurantOrderInteractionType = _initialOrderInteractionType;
}
private void SetInteractionTypeToRestaurantOrder()
{
_interactionType = InteractionType.RestaurantOrder;
}
public override InteractionType GetInteractionType()
{
return InteractionType.RestaurantOrder;
}
public override bool CanInteract()
{
// 현재 RestaurantOrderInteractionType를 수행할 수 있는지?
if (GetInteractionSubsystemType() == RestaurantOrderInteractionType.WaitCustomer)
{
// Check WaitCustomer
return true;
}
return false;
}
public override bool OnInteracted(IInteractor interactor, ScriptableObject payloadSo = null)
{
// _currentRestaurantOrderInteractionType에 따라 동작이 달라지겠지
if (GetInteractionSubsystemType() == RestaurantOrderInteractionType.WaitCustomer)
{
// DO WAIT CUSTOMER
}
return base.OnInteracted(interactor, payloadSo);
}
public override void InitializeInteraction(InteractionType interactionType)
{
// RestaurantOrderInteractionType에 따른 동작들을 초기화
// Initialize WaitCustomer actions
base.InitializeInteraction(interactionType);
}
public RestaurantOrderInteractionType GetInteractionSubsystemType()
{
return _currentRestaurantOrderInteractionType;
}
}
}

View File

@ -0,0 +1,59 @@
using System;
using UnityEngine;
namespace DDD
{
[Flags]
public enum RestaurantOrderType : uint
{
Wait = 0,
Order = 1u << 0,
Serve = 1u << 1,
}
public class RestaurantOrderInteractionSubsystem : MonoBehaviour, IInteractionSubsystemObject<RestaurantOrderType>
{
[SerializeField] protected RestaurantOrderType orderType = RestaurantOrderType.Wait;
private RestaurantOrderType currentRestaurantOrderType;
public Type GetSubsystemEnumType() => typeof(RestaurantOrderType);
private void Start()
{
currentRestaurantOrderType = orderType;
}
public bool CanInteract()
{
// 현재 RestaurantOrderInteractionType를 수행할 수 있는지?
if (GetInteractionSubsystemType() == RestaurantOrderType.Wait)
{
Debug.Assert(false); // TODO
// Check WaitCustomer
return true;
}
return false;
}
public bool OnInteracted(IInteractor interactor, ScriptableObject payloadSo = null)
{
// _currentRestaurantOrderInteractionType에 따라 동작이 달라지겠지
if (GetInteractionSubsystemType() == RestaurantOrderType.Wait)
{
// DO WAIT CUSTOMER
}
return true;
}
public void InitializeSubsystem()
{
}
public RestaurantOrderType GetInteractionSubsystemType()
{
return currentRestaurantOrderType;
}
}
}

View File

@ -1,19 +1,49 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Sirenix.OdinInspector;
namespace DDD
{
public static class RestaurantInteractionSubsystems
{
public static Dictionary<InteractionType, Type> TypeToSubsystem = new()
{
{InteractionType.RestaurantOrder, typeof(RestaurantOrderInteractionSubsystem)}
};
}
public class RestaurantInteractionComponent : MonoBehaviour, IInteractable
{
// Single interaction type
[ValueDropdown("GetAllInteractionTypes")]
[SerializeField] protected InteractionType _interactionType = InteractionType.None;
[SerializeField] protected InteractionExecutionParameters _executionParameters = new InteractionExecutionParameters(1f);
[SerializeField] protected InteractionDisplayParameters _displayParameters = new InteractionDisplayParameters("");
[SerializeField] protected GameFlowState _interactionAvailableFlows;
[SerializeField] private Transform[] _aiInteractionPoints;
private Dictionary<InteractionType, IInteractionSubsystemObject> _subsystems = new();
private static IEnumerable GetAllInteractionTypes()
{
return System.Enum.GetValues(typeof(InteractionType))
.Cast<InteractionType>()
.Where(x => x != InteractionType.All); // All은 제외
}
public virtual bool CanInteract()
{
return !IsInteractionHidden();
bool isInteractionVisible = !IsInteractionHidden();
bool hasValidSubsystem = true;
if (HasSubsystem(_interactionType))
{
hasValidSubsystem = GetSubsystem(_interactionType).CanInteract();
}
return isInteractionVisible && hasValidSubsystem;
}
public virtual bool IsInteractionHidden()
@ -31,6 +61,10 @@ public virtual bool OnInteracted(IInteractor interactor, ScriptableObject payloa
}
bool interactionResult = RestaurantInteractionEvents.RestaurantInteraction.RequestInteraction(interactor.GetInteractorGameObject(),
GetInteractableGameObject(), GetInteractionType(), payloadSo, true);
if (HasSubsystem(_interactionType))
{
interactionResult &= GetSubsystem(_interactionType).OnInteracted(interactor, payloadSo);
}
return interactionResult;
}
@ -47,6 +81,33 @@ public GameObject GetInteractableGameObject()
public virtual void InitializeInteraction(InteractionType interactionType)
{
_interactionType = interactionType;
InitializeSubsystems();
}
private void InitializeSubsystems()
{
// Initialize Interaction Subsystems
bool hasSubsystemType = RestaurantInteractionSubsystems.TypeToSubsystem.TryGetValue(_interactionType, out var subsystemType);
if (!hasSubsystemType) return;
var subsystem = gameObject.GetComponent(subsystemType) as IInteractionSubsystemObject;
if (subsystem == null)
{
subsystem = gameObject.AddComponent(subsystemType) as IInteractionSubsystemObject;
}
_subsystems.Add(_interactionType, subsystem);
subsystem?.InitializeSubsystem();
}
private bool HasSubsystem(InteractionType interactionType)
{
return _subsystems.ContainsKey(interactionType);
}
private IInteractionSubsystemObject GetSubsystem(InteractionType interactionType)
{
return _subsystems.GetValueOrDefault(interactionType) as IInteractionSubsystemObject;
}
// 새로운 스트럭트 기반 메서드들

View File

@ -1,48 +1,56 @@
using System;
using System.Collections.Generic;
using DDD.RestaurantOrders;
using UnityEngine;
namespace DDD
{
public class RestaurantOrderSolver : MonoBehaviour, IInteractionSolver, IInteractionSubsystemSolver<RestaurantOrderInteractionType>
public static class RestaurantOrderSolvers
{
public static Dictionary<RestaurantOrderType, Type> TypeToOrderSolver = new()
{
{ RestaurantOrderType.Wait, typeof(RestaurantOrderSolver_Wait) },
{ RestaurantOrderType.Order, typeof(RestaurantOrderSolver_Order) },
{ RestaurantOrderType.Serve, typeof(RestaurantOrderSolver_Serve) }
};
}
public class RestaurantOrderSolver : MonoBehaviour, IInteractionSolver
{
private Dictionary<RestaurantOrderType, IInteractionSubsystemSolver<RestaurantOrderType>> _solvers = new();
private void Start()
{
foreach (var orderSolver in RestaurantOrderSolvers.TypeToOrderSolver)
{
var solver = (IInteractionSubsystemSolver<RestaurantOrderType>)gameObject.AddComponent(orderSolver.Value);
_solvers.Add(orderSolver.Key, solver);
}
}
public bool ExecuteInteraction(IInteractor interactor, IInteractable interactable, ScriptableObject payloadSo = null)
{
return ExecuteInteractionSubsystem(interactor, interactable, payloadSo);
return TryGetSolver(interactable, out var solver) &&
solver.ExecuteInteractionSubsystem(interactor, interactable, payloadSo);
}
public bool CanExecuteInteraction(IInteractor interactor = null, IInteractable interactable = null,
ScriptableObject payloadSo = null)
{
return CanExecuteInteractionSubsystem(interactor, interactable, payloadSo);
return TryGetSolver(interactable, out var solver) &&
solver.CanExecuteInteractionSubsystem(interactor, interactable, payloadSo);
}
public bool ExecuteInteractionSubsystem(IInteractor interactor, IInteractable interactable, ScriptableObject payloadSo = null)
// Solver를 가져오는 공통 로직
private bool TryGetSolver(IInteractable interactable, out IInteractionSubsystemSolver<RestaurantOrderType> solver)
{
if (interactable is IInteractionSubsystemObject<RestaurantOrderInteractionType> subsystem)
{
RestaurantOrderInteractionType interactionType = subsystem.GetInteractionSubsystemType();
// Can I solve this interaction type?
if (interactionType == RestaurantOrderInteractionType.WaitCustomer)
{
// DO SOMETHING!!!
return true;
}
}
return false;
}
solver = null;
public bool CanExecuteInteractionSubsystem(IInteractor interactor = null, IInteractable interactable = null,
ScriptableObject payloadSo = null)
{
if (interactable is IInteractionSubsystemObject<RestaurantOrderInteractionType> subsystem)
{
RestaurantOrderInteractionType interactionType = subsystem.GetInteractionSubsystemType();
// Can I solve this interaction type?
if (interactionType == RestaurantOrderInteractionType.WaitCustomer)
{
return true;
}
}
return false;
if (interactable is not IInteractionSubsystemObject<RestaurantOrderType> subsystem)
return false;
var type = subsystem.GetInteractionSubsystemType();
return _solvers.TryGetValue(type, out solver);
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0a7eea23af674c2aa6ffc20bd5801efb
timeCreated: 1755672003

View File

@ -0,0 +1,19 @@
using UnityEngine;
namespace DDD.RestaurantOrders
{
public class RestaurantOrderSolver_Order : MonoBehaviour, IInteractionSubsystemSolver<RestaurantOrderType>
{
public bool ExecuteInteractionSubsystem(IInteractor interactor, IInteractable interactable, ScriptableObject payloadSo = null)
{
// TODO : DO SOMETHING!!!
return true;
}
public bool CanExecuteInteractionSubsystem(IInteractor interactor = null, IInteractable interactable = null,
ScriptableObject payloadSo = null)
{
return true;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3afc1759b02e4230967b3b72fe354ea3
timeCreated: 1755672492

View File

@ -0,0 +1,19 @@
using UnityEngine;
namespace DDD.RestaurantOrders
{
public class RestaurantOrderSolver_Serve : MonoBehaviour, IInteractionSubsystemSolver<RestaurantOrderType>
{
public bool ExecuteInteractionSubsystem(IInteractor interactor, IInteractable interactable, ScriptableObject payloadSo = null)
{
// TODO : DO SOMETHING!!!
return true;
}
public bool CanExecuteInteractionSubsystem(IInteractor interactor = null, IInteractable interactable = null,
ScriptableObject payloadSo = null)
{
return true;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4df15c40347044648623d5932bb0724e
timeCreated: 1755672501

View File

@ -0,0 +1,19 @@
using UnityEngine;
namespace DDD.RestaurantOrders
{
public class RestaurantOrderSolver_Wait : MonoBehaviour, IInteractionSubsystemSolver<RestaurantOrderType>
{
public bool ExecuteInteractionSubsystem(IInteractor interactor, IInteractable interactable, ScriptableObject payloadSo = null)
{
// TODO : DO SOMETHING!!!
return true;
}
public bool CanExecuteInteractionSubsystem(IInteractor interactor = null, IInteractable interactable = null,
ScriptableObject payloadSo = null)
{
return true;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: cc81a22ff98a4b42b45ad27219ec05fa
timeCreated: 1755672371