diff --git a/Assets/_DDD/_Scripts/GameUi/BaseUi.cs b/Assets/_DDD/_Scripts/GameUi/BaseUi.cs index da48fc1dd..33de6cac5 100644 --- a/Assets/_DDD/_Scripts/GameUi/BaseUi.cs +++ b/Assets/_DDD/_Scripts/GameUi/BaseUi.cs @@ -4,8 +4,14 @@ namespace DDD { public abstract class BaseUi : MonoBehaviour { + protected GameObject _panel; public virtual bool IsBlockingTime => false; public virtual bool IsOpen => gameObject.activeSelf; + + protected virtual void Awake() + { + _panel = transform.Find(CommonConstants.Panel).gameObject; + } protected virtual void Start() { @@ -20,7 +26,7 @@ protected virtual void OnDestroy() protected virtual void TryRegister() { } protected virtual void TryUnregister() { } - public virtual void Open() => gameObject.SetActive(true); - public virtual void Close() => gameObject.SetActive(false); + public virtual void Open() => _panel.SetActive(true); + public virtual void Close() => _panel.SetActive(false); } } \ No newline at end of file diff --git a/Assets/_DDD/_Scripts/GameUi/GlobalMessageUi.cs b/Assets/_DDD/_Scripts/GameUi/GlobalMessageUi.cs index 7d08b9621..da527157a 100644 --- a/Assets/_DDD/_Scripts/GameUi/GlobalMessageUi.cs +++ b/Assets/_DDD/_Scripts/GameUi/GlobalMessageUi.cs @@ -14,20 +14,27 @@ public class GlobalMessageUi : BaseUi, IEventHandler private readonly Queue _messageQueue = new(); private bool _isDisplayingMessage = false; - private void Awake() + protected override void Awake() { + base.Awake(); + _canvasGroup = GetComponent(); _messageText = GetComponentInChildren(); _canvasGroup.alpha = 0; _messageText.text = null; + } + + protected override void TryRegister() + { + base.TryRegister(); EventBus.Register(this); } - protected override void OnDestroy() + protected override void TryUnregister() { - base.OnDestroy(); + base.TryUnregister(); EventBus.Unregister(this); _fadeTween?.Kill(); diff --git a/Assets/_DDD/_Scripts/GameUi/PopupUi.cs b/Assets/_DDD/_Scripts/GameUi/PopupUi.cs index 830988d16..a8a976c06 100644 --- a/Assets/_DDD/_Scripts/GameUi/PopupUi.cs +++ b/Assets/_DDD/_Scripts/GameUi/PopupUi.cs @@ -1,7 +1,78 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.InputSystem; + namespace DDD { public class PopupUi : BaseUi { + protected UiInputBindingSo _uiInputBindingSo; + protected readonly List<(InputAction action, Action handler)> _registeredHandlers = new(); + protected override async void TryRegister() + { + base.TryRegister(); + UiManager.Instance.RegisterPopupUI(this); + + // So의 이름을 통일 : TestUi_UiInputBindingSo + string addressableKey = $"{GetType().Name}_{DataConstants.UiInputBindingSo}"; + _uiInputBindingSo = await AssetManager.LoadAsset(addressableKey); + Debug.Assert(_uiInputBindingSo != null, "_uiInputBindingSo != null"); + + foreach (var binding in _uiInputBindingSo.Bindings) + { + if (binding.InputAction == null) continue; + + var action = binding.InputAction.action; + if (action == null) continue; + + var handler = new Action(ctx => + { + if (UiManager.Instance.IsTopPopup(this)) + { + OnInputPerformed(binding.ActionName, ctx); + } + }); + + action.Enable(); + action.performed += handler; + + _registeredHandlers.Add((action, handler)); + } + } + + protected override void TryUnregister() + { + base.TryUnregister(); + UiManager.Instance.UnregisterPopupUI(this); + + foreach (var (action, handler) in _registeredHandlers) + { + if (action != null) + { + action.performed -= handler; + action.Disable(); + } + } + + _registeredHandlers.Clear(); + } + + public override void Open() + { + base.Open(); + + transform.SetAsLastSibling(); + + if (UiManager.Instance.IsTopPopup(this)) + { + InputManager.Instance.SwitchCurrentActionMap(_uiInputBindingSo.InputActionMaps); + } + } + + protected virtual void OnInputPerformed(string actionName, InputAction.CallbackContext ctx) { } + + public InputActionMaps GetInputActionMaps() => _uiInputBindingSo.InputActionMaps; } } \ No newline at end of file diff --git a/Assets/_DDD/_Scripts/GameUi/UiManager.cs b/Assets/_DDD/_Scripts/GameUi/UiManager.cs index eaeccd36b..4e0eaf487 100644 --- a/Assets/_DDD/_Scripts/GameUi/UiManager.cs +++ b/Assets/_DDD/_Scripts/GameUi/UiManager.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; namespace DDD @@ -7,6 +8,8 @@ namespace DDD public class UiManager : Singleton, IManager, IEventHandler, IEventHandler { private readonly Dictionary _popupUIs = new(); + private readonly Stack _popupStack = new(); + private InputActionMaps _previousActionMap = InputActionMaps.None; private readonly object _uiPauseRequester = new(); @@ -51,14 +54,18 @@ public void Invoke(OpenPopupUiEvent evt) { if (_popupUIs.TryGetValue(evt.UiType, out var popup)) { - popup.Open(); - - if (popup.IsBlockingTime) + if (!popup.IsOpen) { - var timeScaleChangeEvent = GameEvents.RequestTimeScaleChangeEvent; - timeScaleChangeEvent.Requester = popup; - timeScaleChangeEvent.NewTimeScale = 0f; - EventBus.Broadcast(timeScaleChangeEvent); + popup.Open(); + PushPopup(popup); + + if (popup.IsBlockingTime) + { + var timeScaleChangeEvent = GameEvents.RequestTimeScaleChangeEvent; + timeScaleChangeEvent.Requester = popup; + timeScaleChangeEvent.NewTimeScale = 0f; + EventBus.Broadcast(timeScaleChangeEvent); + } } } } @@ -67,16 +74,65 @@ public void Invoke(ClosePopupUiEvent evt) { if (_popupUIs.TryGetValue(evt.UiType, out var popup)) { - popup.Close(); - - if (popup.IsBlockingTime) + if (popup.IsOpen) { - var timeScaleChangeEvent = GameEvents.RequestTimeScaleChangeEvent; - timeScaleChangeEvent.Requester = popup; - timeScaleChangeEvent.NewTimeScale = 1f; - EventBus.Broadcast(timeScaleChangeEvent); + popup.Close(); + PopPopup(popup); + + if (popup.IsBlockingTime) + { + var timeScaleChangeEvent = GameEvents.RequestTimeScaleChangeEvent; + timeScaleChangeEvent.Requester = popup; + timeScaleChangeEvent.NewTimeScale = 1f; + EventBus.Broadcast(timeScaleChangeEvent); + } } } } + + public bool IsTopPopup(PopupUi popup) + { + return _popupStack.Count > 0 && _popupStack.Peek() == popup; + } + + public void PushPopup(PopupUi popup) + { + if (_popupStack.Contains(popup)) return; + + if (_popupStack.Count == 0) + { + _previousActionMap = InputManager.Instance.GetCurrentActionMap(); + } + + _popupStack.Push(popup); + } + + public void PopPopup(PopupUi popup) + { + if (_popupStack.Count == 0) return; + + if (_popupStack.Peek() == popup) + { + _popupStack.Pop(); + } + else + { + var temp = _popupStack.Reverse().Where(p => p != popup).Reverse().ToList(); + _popupStack.Clear(); + foreach (var p in temp) + { + _popupStack.Push(p); + } + } + + if (_popupStack.TryPeek(out var topPopup) && topPopup.IsOpen) + { + InputManager.Instance.SwitchCurrentActionMap(topPopup.GetInputActionMaps()); + } + else + { + InputManager.Instance.SwitchCurrentActionMap(_previousActionMap); + } + } } } \ No newline at end of file diff --git a/Assets/_DDD/_Scripts/InputSystem/InputManager.cs b/Assets/_DDD/_Scripts/InputSystem/InputManager.cs index c39d3a2df..73924ae98 100644 --- a/Assets/_DDD/_Scripts/InputSystem/InputManager.cs +++ b/Assets/_DDD/_Scripts/InputSystem/InputManager.cs @@ -1,50 +1,44 @@ using System; +using System.Threading.Tasks; using UnityEngine; using UnityEngine.InputSystem; namespace DDD { + public static class InputActionMapExtensions + { + public static string ToName(this InputActionMaps map) + { + return map.ToString(); + } + } + public enum InputActionMaps { None = 0, Ui = 1, Restaurant = 2, - } - - [Flags] - public enum RestaurantActions - { - None = 0, - Move = 1<<0, - Dash = 1<<1, - Interact = 1<<2 + RestaurantUi = 3 } - public class InputManager : Singleton + public class InputManager : Singleton, IManager { private PlayerInput _currentPlayerInput; - - protected override void OnAwake() + + public void PreInit() { - base.OnAwake(); - _currentPlayerInput = GetComponent(); } - - // public void ChangeScene(SceneType sceneType) - // { - // switch (sceneType) - // { - // case SceneType.Title: - // SwitchCurrentActionMap(InputActionMaps.Ui); - // break; - // case SceneType.Restaurant: - // SwitchCurrentActionMap(InputActionMaps.Restaurant); - // break; - // default: - // throw new System.Exception("Invalid scene name"); - // } - // } + + public Task Init() + { + return Task.CompletedTask; + } + + public void PostInit() + { + + } private bool IsNullCurrentPlayerInput() { @@ -54,193 +48,25 @@ private bool IsNullCurrentPlayerInput() return true; } - public InputAction GetAction(InputActionMaps actionMapName, string actionName) - { - if (IsNullCurrentPlayerInput()) return null; - - var actionMap = _currentPlayerInput.actions.FindActionMap(actionMapName.ToString(), true); - if (actionMap == null) - { - Debug.LogError($"Action Map '{actionMapName}' not found!"); - return null; - } - - var action = actionMap.FindAction(actionName, true); - if (action == null) - { - Debug.LogError($"Action '{actionName}' not found in Action Map '{actionMapName}'!"); - } - - return action; - } - - public string GetBoundKey(InputActionMaps actionMapName, string actionName) - { - if (IsNullCurrentPlayerInput()) return null; - - var actionMap = _currentPlayerInput.actions.FindActionMap(actionMapName.ToString(), true); - if (actionMap == null) - { - Debug.LogError($"Action Map '{actionMapName}' not found!"); - return null; - } - - var action = actionMap.FindAction(actionName, true); - if (action == null) - { - Debug.LogError($"Action '{actionName}' not found in Action Map '{actionMapName}'!"); - return null; - } - - // 첫 번째 바인딩에서 키 이름 가져오기 - foreach (var binding in action.bindings) - { - if (!string.IsNullOrEmpty(binding.path)) - { - // 키 이름만 추출 - var key = InputControlPath.ToHumanReadableString(binding.path, - InputControlPath.HumanReadableStringOptions.OmitDevice); - return key; - } - } - - Debug.LogWarning($"No bindings found for action '{actionName}' in Action Map '{actionMapName}'."); - return null; - } - - public string GetBoundKey(InputAction inputAction) - { - if (IsNullCurrentPlayerInput()) return null; - - if (inputAction == null) - { - Debug.LogError($"Action not found'!"); - return null; - } - - // 첫 번째 바인딩에서 키 이름 가져오기 - foreach (var binding in inputAction.bindings) - { - if (!string.IsNullOrEmpty(binding.path)) - { - // 키 이름만 추출 - var key = InputControlPath.ToHumanReadableString(binding.path, - InputControlPath.HumanReadableStringOptions.OmitDevice); - return key; - } - } - - Debug.LogWarning($"No bindings found for action '{inputAction}'"); - return null; - } - - public bool IsCurrentActionMap(InputActionMaps inputActionMaps) - { - if (IsNullCurrentPlayerInput()) return false; - - return _currentPlayerInput.currentActionMap.ToString() == inputActionMaps.ToString(); - } - - public void SwitchCurrentActionMap(string inputActionMaps) - { - if (IsNullCurrentPlayerInput()) return; - - _currentPlayerInput.SwitchCurrentActionMap(inputActionMaps); - } - public void SwitchCurrentActionMap(InputActionMaps inputActionMaps) { - if (IsNullCurrentPlayerInput()) return; + if (IsNullCurrentPlayerInput() || inputActionMaps == InputActionMaps.None) return; - _currentPlayerInput.SwitchCurrentActionMap(inputActionMaps.ToString()); + _currentPlayerInput.SwitchCurrentActionMap(inputActionMaps.ToName()); } - public InputActionMap GetCurrentInputActionMap() + public InputActionMaps GetCurrentActionMap() { - if (IsNullCurrentPlayerInput()) return null; + if (IsNullCurrentPlayerInput()) return InputActionMaps.None; - return _currentPlayerInput.currentActionMap; - } - - public void EnableCurrentPlayerInput() - { - if (!_currentPlayerInput) return; - - _currentPlayerInput.enabled = true; - } - - public void DisableCurrentPlayerInput() - { - if (IsNullCurrentPlayerInput()) return; - - _currentPlayerInput.enabled = false; - } - - public void DisableAllActionMaps() - { - if (IsNullCurrentPlayerInput()) return; - - foreach (var element in _currentPlayerInput.actions.actionMaps) + string mapName = _currentPlayerInput.currentActionMap.name; + if (Enum.TryParse(mapName, out InputActionMaps parsedMap)) { - element.Disable(); + return parsedMap; } - } - - public void DisableAllActionsExcept(string exceptActionName) - { - if (IsNullCurrentPlayerInput()) return; - - var exceptAction = _currentPlayerInput.currentActionMap.FindAction(exceptActionName); - - foreach (var action in _currentPlayerInput.currentActionMap.actions) - { - if (action != exceptAction) - { - action.Disable(); - } - else - { - action.Enable(); - } - } - } - - public void EnableAllActionsMaps() - { - if (IsNullCurrentPlayerInput()) return; - - foreach (var action in _currentPlayerInput.actions) - { - action.Enable(); - } - } - - public void EnableAction(string actionName) - { - if (IsNullCurrentPlayerInput()) return; - - var action = _currentPlayerInput.currentActionMap.FindAction(actionName); - if (action == null) - { - Debug.Log($"현재 Action Map인 {_currentPlayerInput.currentActionMap}에는 {actionName} Action이 존재하지 않습니다"); - return; - } - - action.Enable(); - } - - public void DisableAction(string actionName) - { - if (IsNullCurrentPlayerInput()) return; - - var action = _currentPlayerInput.currentActionMap.FindAction(actionName); - if (action == null) - { - Debug.Log($"현재 Action Map인 {_currentPlayerInput.currentActionMap}에는 {actionName} Action이 존재하지 않습니다"); - return; - } - - action.Disable(); + + Debug.LogError($"[InputManager] 알 수 없는 ActionMap 이름: {mapName}"); + return InputActionMaps.None; } } } \ No newline at end of file diff --git a/Assets/_DDD/_Scripts/InputSystem/UiActionBinding.cs b/Assets/_DDD/_Scripts/InputSystem/UiActionBinding.cs new file mode 100644 index 000000000..1407a73d9 --- /dev/null +++ b/Assets/_DDD/_Scripts/InputSystem/UiActionBinding.cs @@ -0,0 +1,12 @@ +using System; +using UnityEngine.InputSystem; + +namespace DDD +{ + [Serializable] + public class UiActionBinding + { + public string ActionName; + public InputActionReference InputAction; + } +} \ No newline at end of file diff --git a/Assets/_DDD/_Scripts/InputSystem/UiInputBindingSo.cs b/Assets/_DDD/_Scripts/InputSystem/UiInputBindingSo.cs new file mode 100644 index 000000000..6ae102f03 --- /dev/null +++ b/Assets/_DDD/_Scripts/InputSystem/UiInputBindingSo.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace DDD +{ + [CreateAssetMenu(fileName = "UiInputBindingSo", menuName = "Ui/UiInputBindingSo")] + public class UiInputBindingSo : ScriptableObject + { + public InputActionMaps InputActionMaps; + public List Bindings = new(); + } +} \ No newline at end of file diff --git a/Assets/_DDD/_Scripts/RestaurantController/RestaurantController.cs b/Assets/_DDD/_Scripts/RestaurantController/RestaurantController.cs index 67b2afa99..b7e5afb10 100644 --- a/Assets/_DDD/_Scripts/RestaurantController/RestaurantController.cs +++ b/Assets/_DDD/_Scripts/RestaurantController/RestaurantController.cs @@ -70,6 +70,7 @@ public async Task OnReadyNewFlow(GameFlowState newFlowState) var playerHandle = createRestaurantPlayerSoJob.OnReadyNewFlow(newFlowState); var propHandle = createEnvironmentSoJob.OnReadyNewFlow(newFlowState); // Combine handles and return it + InputManager.Instance.SwitchCurrentActionMap(InputActionMaps.Restaurant); await Task.WhenAll(playerHandle, propHandle); } } diff --git a/Assets/_DDD/_Scripts/Utilities/Constants.cs b/Assets/_DDD/_Scripts/Utilities/Constants.cs index 0043760c8..e30f4138f 100644 --- a/Assets/_DDD/_Scripts/Utilities/Constants.cs +++ b/Assets/_DDD/_Scripts/Utilities/Constants.cs @@ -6,6 +6,7 @@ public static class CommonConstants public const string RestaurantPlayer = "RestaurantPlayer"; public const string BaseRestaurantEnvironment = "BaseRestaurantEnvironment"; public const string Clone = "(Clone)"; + public const string Panel = "Panel"; } public static class DataConstants @@ -14,6 +15,7 @@ public static class DataConstants public const string FoodDataSo = "FoodDataSo"; public const string EnvironmentDataSo = "EnvironmentDataSo"; public const string RestaurantPlayerDataSo = "RestaurantPlayerDataSo"; + public const string UiInputBindingSo = "UiInputBindingSo"; public const string AtlasLabel = "Atlas"; public const string BasePropSpriteMaterial = "BasePropSpriteMaterial";