레스토랑 인터랙션 폴더 정리, 인터랙션이 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();
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;
[SerializeField, ReadOnly] protected Collider[] _nearColliders = new Collider[10];
@ -63,7 +68,7 @@ public IInteractable GetFocusedInteractable()
return _nearestInteractable;
}
private bool TryGetSolverFor(IInteractable interactable, out IInteractionSolver solver)
protected bool TryGetSolverFor(IInteractable interactable, out IInteractionSolver solver)
{
solver = null;
if (interactable == null) return false;
@ -71,7 +76,7 @@ private bool TryGetSolverFor(IInteractable interactable, out IInteractionSolver
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;
@ -153,5 +158,17 @@ protected void InitializeInteractionSolvers(Dictionary<InteractionType, Type> ty
public virtual bool IsInteracting() => _interactingTarget != null;
public virtual float GetMovementSpeedMultiplier() => 1f;
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
}
public enum PlayerActionAnimationState
{
None = 0,
CleaningTable = 1,
}
public enum PlayerDefaultAnimationState
{
None = 0,
@ -31,7 +25,7 @@ public class PlayerAnimation : CharacterAnimation
private IMovementState _movementState;
private PlayerTaskAnimationState _currentTaskAnimationState = PlayerTaskAnimationState.None;
private PlayerActionAnimationState _currentActionAnimationState = PlayerActionAnimationState.None;
private CharacterActionState _currentActionState = CharacterActionState.None;
private PlayerDefaultAnimationState _currentDefaultAnimationState = PlayerDefaultAnimationState.None;
private Dictionary<PlayerTaskAnimationState, string> _taskToAnimation = new()
@ -39,9 +33,9 @@ public class PlayerAnimation : CharacterAnimation
{ 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()
@ -90,24 +84,24 @@ private void UpdateAnimations()
// 1순위: Task 애니메이션이 재생 중이면 다른 애니메이션 처리하지 않음
if (_currentTaskAnimationState != PlayerTaskAnimationState.None)
{
_currentActionAnimationState = PlayerActionAnimationState.None;
_currentActionState = CharacterActionState.None;
_currentDefaultAnimationState = PlayerDefaultAnimationState.None;
return;
}
// 2순위: ActionState 체크
var desiredActionState = GetDesiredActionState();
if (desiredActionState == PlayerActionAnimationState.None)
if (desiredActionState == CharacterActionState.None)
{
_currentActionAnimationState = PlayerActionAnimationState.None;
_currentActionState = CharacterActionState.None;
}
else
{
if (_currentActionAnimationState != desiredActionState)
if (_currentActionState != desiredActionState)
{
_currentDefaultAnimationState = PlayerDefaultAnimationState.None;
_currentActionAnimationState = desiredActionState;
PlayActionAnimation(_currentActionAnimationState);
_currentActionState = desiredActionState;
PlayActionAnimation(_currentActionState);
}
return;
}
@ -146,25 +140,21 @@ private async Task PlayTaskAnimation(PlayerTaskAnimationState state, float durat
_currentTaskAnimationState = PlayerTaskAnimationState.None;
}
private PlayerActionAnimationState GetDesiredActionState()
private CharacterActionState GetDesiredActionState()
{
if (_interactor.IsInteracting() == false) return PlayerActionAnimationState.None;
var interactable = _interactor.GetFocusedInteractable();
if (interactable == null) return PlayerActionAnimationState.None;
if (_interactor.IsInteracting() == false) return CharacterActionState.None;
var interactionType = interactable.GetInteractionType();
if (interactionType == InteractionType.RestaurantTrash) // TODO : 서브시스템 연결해서 테이블청소 연결해야함
if (_interactor is ICharacterActionStateProvider actionStateProvider)
{
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);
}

View File

@ -10,7 +10,7 @@ namespace DDD.Restaurant
{
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.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
[ValueDropdown("GetAllInteractionTypes")]
@ -239,5 +246,24 @@ public bool TryGetSubsystemEnumType<T>(out T enumValue) where T : Enum
enumValue = default;
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
{
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>();
if (carrier == null)
@ -14,7 +14,7 @@ public bool ExecuteInteraction(IInteractor interactor, IInteractable interactabl
return true;
}
public bool CanExecuteInteraction(IInteractor interactor = null, IInteractable interactable = null,
public override bool CanExecuteInteraction(IInteractor interactor = null, IInteractable interactable = null,
ScriptableObject payload = null)
{
// Check carrying state
@ -25,7 +25,7 @@ public bool CanExecuteInteraction(IInteractor interactor = null, IInteractable i
return false;
}
public bool CanSolveInteraction(IInteractor interactor, IInteractable interactable)
public override bool CanSolveInteraction(IInteractor interactor, IInteractable interactable)
{
return true;
}

View File

@ -2,9 +2,20 @@
using System.Collections.Generic;
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();
@ -18,19 +29,19 @@ private void Awake()
_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) &&
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) &&
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)
{

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

View File

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

View File

@ -47,7 +47,7 @@ public interface IRestaurantOrderObject
// 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 RestaurantOrderObjectState _orderObjectState = new();
@ -140,5 +140,15 @@ private void OnDestroy()
{
EventBus.Unregister(this);
}
public override CharacterActionState GetCurrentActionState()
{
if (_currentRestaurantOrderType == RestaurantOrderType.Dirty)
{
return CharacterActionState.CleaningTable;
}
return CharacterActionState.None;
}
}
}