레스토랑 인터랙션 폴더 정리, 인터랙션이 CharacterActionState 제공

This commit is contained in:
Jeonghyeon Ha 2025-09-02 16:53:26 +09:00
parent fa6746b93e
commit d66aee7820
55 changed files with 140 additions and 45 deletions

View File

@ -0,0 +1,10 @@
using UnityEngine;
namespace DDD.Restaurant
{
public enum CharacterActionState
{
None = 0,
CleaningTable = 1,
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d2e8668bef454e00a5f8b8cd49919645
timeCreated: 1756795869

View File

@ -11,8 +11,13 @@ public interface IInteractionStateProvider
float GetMovementSpeedMultiplier(); float GetMovementSpeedMultiplier();
bool IsMovementBlocked(); bool IsMovementBlocked();
} }
public interface ICharacterActionStateProvider
{
CharacterActionState GetCurrentActionState();
}
public class CharacterInteraction : MonoBehaviour, IInteractor, IEventHandler<RestaurantInteractionEvent>, IInteractionStateProvider public class CharacterInteraction : MonoBehaviour, IInteractor, IEventHandler<RestaurantInteractionEvent>, IInteractionStateProvider, ICharacterActionStateProvider
{ {
[EnumToggleButtons, SerializeField] protected InteractionType _availableInteractions; [EnumToggleButtons, SerializeField] protected InteractionType _availableInteractions;
[SerializeField, ReadOnly] protected Collider[] _nearColliders = new Collider[10]; [SerializeField, ReadOnly] protected Collider[] _nearColliders = new Collider[10];
@ -63,7 +68,7 @@ public IInteractable GetFocusedInteractable()
return _nearestInteractable; return _nearestInteractable;
} }
private bool TryGetSolverFor(IInteractable interactable, out IInteractionSolver solver) protected bool TryGetSolverFor(IInteractable interactable, out IInteractionSolver solver)
{ {
solver = null; solver = null;
if (interactable == null) return false; if (interactable == null) return false;
@ -71,7 +76,7 @@ private bool TryGetSolverFor(IInteractable interactable, out IInteractionSolver
return TryGetSolverForType(interactable.GetInteractionType(), out solver); return TryGetSolverForType(interactable.GetInteractionType(), out solver);
} }
private bool TryGetSolverForType(InteractionType type, out IInteractionSolver solver) protected bool TryGetSolverForType(InteractionType type, out IInteractionSolver solver)
{ {
if (_cachedSolvers.TryGetValue(type, out solver)) return solver != null; if (_cachedSolvers.TryGetValue(type, out solver)) return solver != null;
@ -153,5 +158,17 @@ protected void InitializeInteractionSolvers(Dictionary<InteractionType, Type> ty
public virtual bool IsInteracting() => _interactingTarget != null; public virtual bool IsInteracting() => _interactingTarget != null;
public virtual float GetMovementSpeedMultiplier() => 1f; public virtual float GetMovementSpeedMultiplier() => 1f;
public virtual bool IsMovementBlocked() => false; public virtual bool IsMovementBlocked() => false;
public CharacterActionState GetCurrentActionState()
{
if (IsInteracting())
{
if(_nearestInteractable is ICharacterActionStateProvider actionStateProvider)
{
return actionStateProvider.GetCurrentActionState();
}
}
return CharacterActionState.None;
}
} }
} }

View File

@ -11,12 +11,6 @@ public enum PlayerTaskAnimationState
Dashing Dashing
} }
public enum PlayerActionAnimationState
{
None = 0,
CleaningTable = 1,
}
public enum PlayerDefaultAnimationState public enum PlayerDefaultAnimationState
{ {
None = 0, None = 0,
@ -31,7 +25,7 @@ public class PlayerAnimation : CharacterAnimation
private IMovementState _movementState; private IMovementState _movementState;
private PlayerTaskAnimationState _currentTaskAnimationState = PlayerTaskAnimationState.None; private PlayerTaskAnimationState _currentTaskAnimationState = PlayerTaskAnimationState.None;
private PlayerActionAnimationState _currentActionAnimationState = PlayerActionAnimationState.None; private CharacterActionState _currentActionState = CharacterActionState.None;
private PlayerDefaultAnimationState _currentDefaultAnimationState = PlayerDefaultAnimationState.None; private PlayerDefaultAnimationState _currentDefaultAnimationState = PlayerDefaultAnimationState.None;
private Dictionary<PlayerTaskAnimationState, string> _taskToAnimation = new() private Dictionary<PlayerTaskAnimationState, string> _taskToAnimation = new()
@ -39,9 +33,9 @@ public class PlayerAnimation : CharacterAnimation
{ PlayerTaskAnimationState.Dashing, "Dash" }, { PlayerTaskAnimationState.Dashing, "Dash" },
}; };
private Dictionary<PlayerActionAnimationState, string> _actionToAnimation = new() private Dictionary<CharacterActionState, string> _actionToAnimation = new()
{ {
{ PlayerActionAnimationState.CleaningTable, "Cleaning/CleaningTable" }, { CharacterActionState.CleaningTable, "Cleaning/CleaningTable" },
}; };
private Dictionary<PlayerDefaultAnimationState, string> _defaultToAnimation = new() private Dictionary<PlayerDefaultAnimationState, string> _defaultToAnimation = new()
@ -90,24 +84,24 @@ private void UpdateAnimations()
// 1순위: Task 애니메이션이 재생 중이면 다른 애니메이션 처리하지 않음 // 1순위: Task 애니메이션이 재생 중이면 다른 애니메이션 처리하지 않음
if (_currentTaskAnimationState != PlayerTaskAnimationState.None) if (_currentTaskAnimationState != PlayerTaskAnimationState.None)
{ {
_currentActionAnimationState = PlayerActionAnimationState.None; _currentActionState = CharacterActionState.None;
_currentDefaultAnimationState = PlayerDefaultAnimationState.None; _currentDefaultAnimationState = PlayerDefaultAnimationState.None;
return; return;
} }
// 2순위: ActionState 체크 // 2순위: ActionState 체크
var desiredActionState = GetDesiredActionState(); var desiredActionState = GetDesiredActionState();
if (desiredActionState == PlayerActionAnimationState.None) if (desiredActionState == CharacterActionState.None)
{ {
_currentActionAnimationState = PlayerActionAnimationState.None; _currentActionState = CharacterActionState.None;
} }
else else
{ {
if (_currentActionAnimationState != desiredActionState) if (_currentActionState != desiredActionState)
{ {
_currentDefaultAnimationState = PlayerDefaultAnimationState.None; _currentDefaultAnimationState = PlayerDefaultAnimationState.None;
_currentActionAnimationState = desiredActionState; _currentActionState = desiredActionState;
PlayActionAnimation(_currentActionAnimationState); PlayActionAnimation(_currentActionState);
} }
return; return;
} }
@ -146,25 +140,21 @@ private async Task PlayTaskAnimation(PlayerTaskAnimationState state, float durat
_currentTaskAnimationState = PlayerTaskAnimationState.None; _currentTaskAnimationState = PlayerTaskAnimationState.None;
} }
private PlayerActionAnimationState GetDesiredActionState() private CharacterActionState GetDesiredActionState()
{ {
if (_interactor.IsInteracting() == false) return PlayerActionAnimationState.None; if (_interactor.IsInteracting() == false) return CharacterActionState.None;
var interactable = _interactor.GetFocusedInteractable();
if (interactable == null) return PlayerActionAnimationState.None;
var interactionType = interactable.GetInteractionType(); if (_interactor is ICharacterActionStateProvider actionStateProvider)
if (interactionType == InteractionType.RestaurantTrash) // TODO : 서브시스템 연결해서 테이블청소 연결해야함
{ {
return PlayerActionAnimationState.CleaningTable; return actionStateProvider.GetCurrentActionState();
} }
return PlayerActionAnimationState.None; return CharacterActionState.None;
} }
private void PlayActionAnimation(PlayerActionAnimationState actionAnimationState) private void PlayActionAnimation(CharacterActionState actionState)
{ {
if (_actionToAnimation.TryGetValue(actionAnimationState, out string animationName)) if (_actionToAnimation.TryGetValue(actionState, out string animationName))
{ {
_spineController.PlayAnimation(animationName, true); _spineController.PlayAnimation(animationName, true);
} }

View File

@ -10,7 +10,7 @@ namespace DDD.Restaurant
{ {
public static class RestaurantInteractionSubsystems public static class RestaurantInteractionSubsystems
{ {
public static Dictionary<InteractionType, Type> TypeToSubsystem = new() public static readonly Dictionary<InteractionType, Type> TypeToSubsystem = new()
{ {
{InteractionType.RestaurantManagement, typeof(InteractionSubsystem_Management)}, {InteractionType.RestaurantManagement, typeof(InteractionSubsystem_Management)},
{InteractionType.RestaurantOrder, typeof(InteractionSubsystem_Order)}, {InteractionType.RestaurantOrder, typeof(InteractionSubsystem_Order)},
@ -18,8 +18,15 @@ public static class RestaurantInteractionSubsystems
}; };
} }
public static class RestaurantInteractionActions
{
public static readonly Dictionary<InteractionType, CharacterActionState> TypeToAction = new()
{
{InteractionType.RestaurantTrash, CharacterActionState.CleaningTable},
};
}
public class RestaurantInteractionComponent : MonoBehaviour, IInteractable, IInteractionSubsystemOwner public class RestaurantInteractionComponent : MonoBehaviour, IInteractable, IInteractionSubsystemOwner, ICharacterActionStateProvider
{ {
// Single interaction type // Single interaction type
[ValueDropdown("GetAllInteractionTypes")] [ValueDropdown("GetAllInteractionTypes")]
@ -239,5 +246,24 @@ public bool TryGetSubsystemEnumType<T>(out T enumValue) where T : Enum
enumValue = default; enumValue = default;
return false; return false;
} }
public CharacterActionState GetCurrentActionState()
{
if (HasSubsystem(_interactionType))
{
var subsystemObject = GetSubsystem(_interactionType);
if(subsystemObject is ICharacterActionStateProvider actionStateProvider)
{
return actionStateProvider.GetCurrentActionState();
}
}
else
{
return RestaurantInteractionActions.TypeToAction.GetValueOrDefault(_interactionType,
CharacterActionState.None);
}
return CharacterActionState.None;
}
} }
} }

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4cc0ab3a0d5b47e2b46992a16ecbbc5a
timeCreated: 1756798057

View File

@ -2,9 +2,9 @@
namespace DDD.Restaurant namespace DDD.Restaurant
{ {
public class RestaurantTrashSolver : MonoBehaviour, IInteractionSolver public class RestaurantTrashSolver : RestaurantBaseSolver
{ {
public bool ExecuteInteraction(IInteractor interactor, IInteractable interactable, ScriptableObject payload = null) public override bool ExecuteInteraction(IInteractor interactor, IInteractable interactable, ScriptableObject payload = null)
{ {
var carrier = interactor?.GetInteractorGameObject()?.GetComponent<ICarrier>(); var carrier = interactor?.GetInteractorGameObject()?.GetComponent<ICarrier>();
if (carrier == null) if (carrier == null)
@ -14,7 +14,7 @@ public bool ExecuteInteraction(IInteractor interactor, IInteractable interactabl
return true; return true;
} }
public bool CanExecuteInteraction(IInteractor interactor = null, IInteractable interactable = null, public override bool CanExecuteInteraction(IInteractor interactor = null, IInteractable interactable = null,
ScriptableObject payload = null) ScriptableObject payload = null)
{ {
// Check carrying state // Check carrying state
@ -25,7 +25,7 @@ public bool CanExecuteInteraction(IInteractor interactor = null, IInteractable i
return false; return false;
} }
public bool CanSolveInteraction(IInteractor interactor, IInteractable interactable) public override bool CanSolveInteraction(IInteractor interactor, IInteractable interactable)
{ {
return true; return true;
} }

View File

@ -2,9 +2,20 @@
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
namespace DDD namespace DDD.Restaurant
{ {
public abstract class RestaurantSubsystemSolver<T> : MonoBehaviour, IInteractionSolver where T : Enum public abstract class RestaurantBaseSolver : MonoBehaviour, IInteractionSolver
{
public abstract bool ExecuteInteraction(IInteractor interactor, IInteractable interactable,
ScriptableObject payload = null);
public abstract bool CanExecuteInteraction(IInteractor interactor = null, IInteractable interactable = null,
ScriptableObject payload = null);
public abstract bool CanSolveInteraction(IInteractor interactor, IInteractable interactable);
}
public abstract class RestaurantSubsystemSolver<T> : RestaurantBaseSolver where T : Enum
{ {
private Dictionary<T, IInteractionSubsystemSolver<T>> _solvers = new(); private Dictionary<T, IInteractionSubsystemSolver<T>> _solvers = new();
@ -18,19 +29,19 @@ private void Awake()
_solvers.Add(subsystemSolverType.Key, solver); _solvers.Add(subsystemSolverType.Key, solver);
} }
} }
public bool ExecuteInteraction(IInteractor interactor, IInteractable interactable, ScriptableObject payload = null) public override bool ExecuteInteraction(IInteractor interactor, IInteractable interactable, ScriptableObject payload = null)
{ {
return TryGetSolver(interactable, out var solver) && return TryGetSolver(interactable, out var solver) &&
solver.ExecuteInteractionSubsystem(interactor, interactable, payload); solver.ExecuteInteractionSubsystem(interactor, interactable, payload);
} }
public bool CanExecuteInteraction(IInteractor interactor = null, IInteractable interactable = null, ScriptableObject payload = null) public override bool CanExecuteInteraction(IInteractor interactor = null, IInteractable interactable = null, ScriptableObject payload = null)
{ {
return TryGetSolver(interactable, out var solver) && return TryGetSolver(interactable, out var solver) &&
solver.CanExecuteInteractionSubsystem(interactor, interactable, payload); solver.CanExecuteInteractionSubsystem(interactor, interactable, payload);
} }
public bool CanSolveInteraction(IInteractor interactor, IInteractable interactable) public override bool CanSolveInteraction(IInteractor interactor, IInteractable interactable)
{ {
if (interactable is IInteractionSubsystemOwner subsystemOwner) if (interactable is IInteractionSubsystemOwner subsystemOwner)
{ {

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 889bc878e70343cab7416f799f767451
timeCreated: 1756798128

View File

@ -0,0 +1,9 @@
using UnityEngine;
namespace DDD.Restaurant
{
public abstract class InteractionSubsystemBase : MonoBehaviour, ICharacterActionStateProvider
{
public abstract CharacterActionState GetCurrentActionState();
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d9f52d1cd4bd4917a884b6e3bc1152e7
timeCreated: 1756798490

View File

@ -1,7 +1,7 @@
using System; using System;
using UnityEngine; using UnityEngine;
namespace DDD namespace DDD.Restaurant
{ {
[Flags] [Flags]
public enum RestaurantCookType : uint public enum RestaurantCookType : uint
@ -9,7 +9,7 @@ public enum RestaurantCookType : uint
StartCooking = 0, StartCooking = 0,
} }
public class InteractionSubsystem_Cook : MonoBehaviour, IInteractionSubsystemObject<RestaurantCookType> public class InteractionSubsystem_Cook : InteractionSubsystemBase, IInteractionSubsystemObject<RestaurantCookType>
{ {
[SerializeField] protected RestaurantCookType _cookType = RestaurantCookType.StartCooking; [SerializeField] protected RestaurantCookType _cookType = RestaurantCookType.StartCooking;
@ -42,5 +42,10 @@ public string GetCurrentSubsystemTypeName()
{ {
return _cookType.ToString(); return _cookType.ToString();
} }
public override CharacterActionState GetCurrentActionState()
{
return CharacterActionState.None;
}
} }
} }

View File

@ -1,7 +1,7 @@
using System; using System;
using UnityEngine; using UnityEngine;
namespace DDD namespace DDD.Restaurant
{ {
[Flags] [Flags]
public enum RestaurantManagementType : uint public enum RestaurantManagementType : uint
@ -10,7 +10,7 @@ public enum RestaurantManagementType : uint
RunRestaurant = 1, RunRestaurant = 1,
} }
public class InteractionSubsystem_Management : MonoBehaviour, IInteractionSubsystemObject<RestaurantManagementType> public class InteractionSubsystem_Management : InteractionSubsystemBase, IInteractionSubsystemObject<RestaurantManagementType>
{ {
[SerializeField] protected RestaurantManagementType _managementType = RestaurantManagementType.OpenManagementUi; [SerializeField] protected RestaurantManagementType _managementType = RestaurantManagementType.OpenManagementUi;
@ -48,5 +48,10 @@ public ScriptableObject GetPayload()
{ {
return null; return null;
} }
public override CharacterActionState GetCurrentActionState()
{
return CharacterActionState.None;
}
} }
} }

View File

@ -47,7 +47,7 @@ public interface IRestaurantOrderObject
// TODO : 도중에 이탈할 경우, 순차적으로 다음 페이즈로 넘어가는 게 아니라 바로 Wait, Dirty로 전이시킬 필요가 있음 // TODO : 도중에 이탈할 경우, 순차적으로 다음 페이즈로 넘어가는 게 아니라 바로 Wait, Dirty로 전이시킬 필요가 있음
public class InteractionSubsystem_Order : MonoBehaviour, IInteractionSubsystemObject<RestaurantOrderType>, IRestaurantOrderObject, IEventHandler<RestaurantOrderInterrupt> public class InteractionSubsystem_Order : InteractionSubsystemBase, IInteractionSubsystemObject<RestaurantOrderType>, IRestaurantOrderObject, IEventHandler<RestaurantOrderInterrupt>
{ {
[SerializeField] private RestaurantOrderType _currentRestaurantOrderType = RestaurantOrderType.Wait; [SerializeField] private RestaurantOrderType _currentRestaurantOrderType = RestaurantOrderType.Wait;
[SerializeField] private RestaurantOrderObjectState _orderObjectState = new(); [SerializeField] private RestaurantOrderObjectState _orderObjectState = new();
@ -140,5 +140,15 @@ private void OnDestroy()
{ {
EventBus.Unregister(this); EventBus.Unregister(this);
} }
public override CharacterActionState GetCurrentActionState()
{
if (_currentRestaurantOrderType == RestaurantOrderType.Dirty)
{
return CharacterActionState.CleaningTable;
}
return CharacterActionState.None;
}
} }
} }