## UI 面板栈(UIPanelStack)技术说明 目标:统一管理“按 ESC 关闭”的 UI 面板顺序,避免关错面板;并支持“栈为空时按 ESC 打开暂停菜单”。 ### 一、脚本清单 - 面板类型枚举:[UIPanelKind.cs](file:///e:/Unity/Unity%20Program/Test_2022/Assets/_Project/Scripts/UI/PanelStack/UIPanelKind.cs) - 面板栈:[UIPanelStack.cs](file:///e:/Unity/Unity%20Program/Test_2022/Assets/_Project/Scripts/UI/PanelStack/UIPanelStack.cs) - ESC 输入监听:[UIPanelStackInput.cs](file:///e:/Unity/Unity%20Program/Test_2022/Assets/_Project/Scripts/UI/PanelStack/UIPanelStackInput.cs) ### 二、运行机制 - `UIPanelStack` 维护一个栈(List),每个条目包含: - `kind`:面板类型(用于后续扩展/调试) - `root`:面板根 GameObject - `closeAction`:关闭函数(优先使用;没有则默认 SetActive(false)) - `UIPanelStackInput` 每帧检测 ESC: - 若栈非空:关闭栈顶 - 若栈为空:调用 `TryOpenOnEscapeWhenEmpty()`(由暂停菜单注册) ### 三、核心 API - `Push(UIPanelKind kind, GameObject root, Action closeAction)` - 打开面板后调用,入栈。 - 同一个 root 会先 Remove 再 Push,保证栈内不重复。 - `Remove(GameObject root)` - 面板主动关闭时调用,避免栈里残留。 - `CloseTop()` - 关闭栈顶;会清理 inactive/root=null 的条目以防误关。 - `SetEscapeOpenHandler(Func handler)` - 用于“栈为空时按 ESC 打开某个 UI”(例如 InGame 暂停菜单)。 ### 四、项目内的接入点(已实现) - Settings 面板: - `SettingsController.OpenAtIndex(0)` 会 `Push(Settings, root, CloseOrBack)` - `CloseOrBack()` 会 `Remove(root)` - 相关实现:[SettingsController.cs](file:///e:/Unity/Unity%20Program/Test_2022/Assets/_Project/Scripts/UI/Settings/SettingsController.cs) - InGame 暂停菜单: - `InGamePauseMenuController.OnEnable()` 注册 `SetEscapeOpenHandler(TryOpenFromEscape)` - 菜单打开时 Push(Pause, root, Close) - 相关实现:[InGamePauseMenuController.cs](file:///e:/Unity/Unity%20Program/Test_2022/Assets/_Project/Scripts/UI/PauseMenu/InGamePauseMenuController.cs) - 自动创建: - `SettingsBootstrap` 会确保 UIPanelStack/UIPanelStackInput 存在(DontDestroyOnLoad) - 相关实现:[SettingsBootstrap.cs](file:///e:/Unity/Unity%20Program/Test_2022/Assets/_Project/Scripts/Core/SettingsSystem/SettingsBootstrap.cs) ### 五、使用规范(避免关错面板) 1) 只把“需要被 ESC 管理”的 UI 入栈(例如设置、暂停、弹窗) 2) 面板关闭时必须 Remove(或让 root 直接 inactive 也可,栈会清理,但 Remove 更确定) 3) 不在多个系统里各自监听 ESC 直接关 UI;统一交给 UIPanelStackInput 处理