Ui 시스템 구조 강화
This commit is contained in:
parent
4d9fd78c3a
commit
aae35a3563
@ -4,9 +4,15 @@ 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()
|
||||
{
|
||||
TryRegister();
|
||||
@ -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);
|
||||
}
|
||||
}
|
@ -14,20 +14,27 @@ public class GlobalMessageUi : BaseUi, IEventHandler<ShowGlobalMessageEvent>
|
||||
private readonly Queue<ShowGlobalMessageEvent> _messageQueue = new();
|
||||
private bool _isDisplayingMessage = false;
|
||||
|
||||
private void Awake()
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
|
||||
_canvasGroup = GetComponent<CanvasGroup>();
|
||||
_messageText = GetComponentInChildren<TextMeshProUGUI>();
|
||||
|
||||
_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();
|
||||
|
@ -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<InputAction.CallbackContext> 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<UiInputBindingSo>(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<InputAction.CallbackContext>(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;
|
||||
}
|
||||
}
|
@ -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<UiManager>, IManager, IEventHandler<OpenPopupUiEvent>, IEventHandler<ClosePopupUiEvent>
|
||||
{
|
||||
private readonly Dictionary<Type, PopupUi> _popupUIs = new();
|
||||
private readonly Stack<PopupUi> _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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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,
|
||||
RestaurantUi = 3
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum RestaurantActions
|
||||
{
|
||||
None = 0,
|
||||
Move = 1<<0,
|
||||
Dash = 1<<1,
|
||||
Interact = 1<<2
|
||||
}
|
||||
|
||||
public class InputManager : Singleton<InputManager>
|
||||
public class InputManager : Singleton<InputManager>, IManager
|
||||
{
|
||||
private PlayerInput _currentPlayerInput;
|
||||
|
||||
protected override void OnAwake()
|
||||
public void PreInit()
|
||||
{
|
||||
base.OnAwake();
|
||||
|
||||
_currentPlayerInput = GetComponent<PlayerInput>();
|
||||
}
|
||||
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
return parsedMap;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/_DDD/_Scripts/InputSystem/UiActionBinding.cs
Normal file
12
Assets/_DDD/_Scripts/InputSystem/UiActionBinding.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
namespace DDD
|
||||
{
|
||||
[Serializable]
|
||||
public class UiActionBinding
|
||||
{
|
||||
public string ActionName;
|
||||
public InputActionReference InputAction;
|
||||
}
|
||||
}
|
12
Assets/_DDD/_Scripts/InputSystem/UiInputBindingSo.cs
Normal file
12
Assets/_DDD/_Scripts/InputSystem/UiInputBindingSo.cs
Normal file
@ -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<UiActionBinding> Bindings = new();
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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";
|
||||
|
Loading…
Reference in New Issue
Block a user