UI 系统

This commit is contained in:
2026-06-08 11:26:17 +08:00
parent 1897658a00
commit b582317692
94 changed files with 33540 additions and 3726 deletions

View File

@@ -0,0 +1,197 @@
# 75 · 菜单布局与操作逻辑对照 + 改造方案
> 目标:将暂停 / 背包 / 地图 / 护符 / 能力等游戏内菜单的**组成布局逻辑**与**打开-关闭-切换操作逻辑**,对齐业界横版动作冒险标杆作的交互范式,同时**保留本项目独有玩法**(三形态切换、形态下的魂技能 / 魄技能、无"工具(Tools)"系统)。
>
> 本文档只定义信息架构与交互契约,不照搬任何标杆作的玩法系统。
> 命名 / 目录 / Addressable / Layer 一律遵守 `Docs/Standards/`;所有搭建走 `Assets/_Game/Scripts/Editor` 脚手架,不裸建。
相关文档:`Docs/Design/10_UISystem.md``Docs/Design/74_UIScreenFlowDocument.md``Docs/Design/16_MapSystem.md``Docs/DesignSpec/06_FormSystem.md``Docs/DesignSpec/10_UISystem.md`
---
## 0. 一句话结论
架构已到位统一导航栈、L/R 切 Tab、暗雾地图、确认弹窗、数据驱动配置都有。差距在**信息架构**:当前存在"暂停按钮菜单"与"背包 Tab Hub"两条并行入口、内容重叠;目标是把游戏内一切**查看/装备类**面板收敛进**统一 Tab 屏**,暂停退化为薄覆盖层。再补一个缺失的**图鉴**面板。本质是**收敛接线 + 补面板**,新代码很少。
---
## 1. 对标范围界定
| 维度 | 是否参考标杆 | 说明 |
|---|---|---|
| 菜单**布局结构**Tab 划分、层级) | ✅ 参考 | 一键进入带 Tab 的统一屏 |
| **操作逻辑**(开/关/切 Tab/回退/焦点) | ✅ 参考 | 同键开关、L/R 切页、B 逐层退、手柄全程可达 |
| **地图**面板形态 | ✅ 完全参考 | 暗雾、Pin、传送、缩放居中 |
| 玩法系统(护符/工具/资源) | ❌ 用本项目自有 | 无 Tools护符保持现有凹槽模型资源为灵力/魄元而非"丝/念珠" |
| 技能呈现 | 本项目原创 | 三形态 × 魂技能/魄技能,标杆作无此概念,作为独立 Tab 承载 |
---
## 2. 当前实现现状(事实基线)
### 2.1 两条入口
| 入口 | 触发链 | 落点 |
|---|---|---|
| **暂停** | Gameplay `Pause` Action → `EVT_PauseRequested``UIManager.TogglePause()``OpenPanel(PanelId.Pause)` | `DataDrivenPauseMenuController`(竖排按钮,数据驱动) |
| **背包** | Gameplay `Inventory` Action → `EVT_InventoryOpen``OpenPanel(PanelId.Inventory)` | `InventoryHubPanel`Tab HubL/R 肩键切页) |
| 地图(独立) | `EVT_MapOpen` / `EVT_FastTravelOpen``OpenPanel(PanelId.Map)` | `MapPanel`(独立面板,**不在 Hub 内** |
| 护符(独立) | `EVT_CharmPanelOpen``OpenPanel(PanelId.CharmPanel)` | `CharmEquipPanel`(独立面板) |
**问题**:暂停菜单的按钮可用 `PauseMenuAction.OpenPanel``FormSkills / Abilities / Map`;而这些又能作为 Hub 的 Tab。**同一内容两套入口、两种布局**,是与标杆范式最大的结构偏差。
### 2.2 已有面板与 PanelId
`PanelId``UIManager.cs``Pause, Settings, Map, Shop, CharmPanel, SpellSelect, Inventory, FormSkills, Abilities`
| 面板 | 脚本 | 现状 |
|---|---|---|
| 暂停 | `Menus/DataDrivenPauseMenuController.cs` | ✅ 数据驱动 |
| 背包 Hub | `Inventory/InventoryHubPanel.cs` | ✅ Tab 容器(注释规划 Map/Inventory/Tools/Journal/Quests/Options |
| 物品 | `Inventory/ItemInventoryPanel.cs` | ✅ 网格+详情(仅展示) |
| 任务 | `Inventory/QuestLogPanel.cs` | ✅ 存在 |
| 护符 | `CharmEquipPanel.cs` + `CharmCardView.cs` | ✅ 凹槽装备 |
| 地图 | `World/Map/MapPanel.cs` | ✅ 暗雾/Pin/传送/定位器门控 |
| 形态技能 | `FormSkillPanel.cs` | ✅ 三形态 × 魂/魄(只读) |
| 能力总览 | `DataDrivenAbilityPanel.cs` + `AbilityCellView.cs` | ✅ 数据驱动解锁态 |
| 设置 | `Settings/DataDrivenSettingsPanel.cs` | ✅ 数据驱动 |
| **图鉴(Bestiary)** | — | ❌ **缺失** |
### 2.3 已具备的操作逻辑(无需重做)
- 统一导航栈 `UINavigator`Push/Pop、焦点保存恢复、Modal 屏蔽下层、场景卸载清栈。
- 取消归口UI map `Cancel`ESC / 手柄 B`EVT_UICancelPressed` → 导航器关栈顶一层。
- Tab 切换:`InventoryHubPanel` 监听 `EVT_InventoryTabNext/Prev`UI map 肩键)+ 头部按钮点击;焦点委托给 Tab 内容(若实现 `IFocusable`)。
- 地图专用键:`CycleMinimapZoom``MapCenter`
---
## 3. 标杆范式要点(交互参考,去玩法)
1. **单键进统一屏**:一个键打开带横向 Tab 的菜单屏同键再按关闭toggle
2. **L/R 肩键循环 Tab**Tab 头显示名称 + 肩键提示字形(随输入设备切换 KB/手柄图标)。
3. **地图可独立直达**:地图键直接打开"统一屏并定位到地图 Tab"。
4. **B/Circle/ESC 逐层回退**:先关子详情,再关整屏。
5. **暂停是薄覆盖**:游戏冻结、半透明,仅 Resume / Options / Return / Quit**不承载查看类面板**。
6. **手柄全程可达**:每个 Tab/列表进入即有默认焦点。
---
## 4. 逐项对照(符合度)
| 范式要点 | 当前 | 符合度 | 差距 |
|---|---|---|---|
| 单键进统一 Tab 屏 | 有 Hub但内容也散落在暂停菜单 | ⚠️ 部分 | 入口重叠,需收敛 |
| 同键 toggle 关闭 | `OpenInventory` 只 Push 不 toggle | ⚠️ 部分 | 缺再按关闭 |
| L/R 切 Tab + 头部字形提示 | L/R 已有;字形提示未确认 | ⚠️ 部分 | Tab 头补设备图标提示 |
| 地图键直达地图 Tab | 地图是**独立面板**,与 Hub 并行 | ❌ 不符 | 地图应作为 Tab地图键打开 Hub 并选中地图 Tab |
| B/ESC 逐层回退 | `UINavigator` 已实现 | ✅ 符合 | — |
| 暂停薄覆盖、不含查看面板 | 暂停菜单含 `OpenPanel` 跳转项 | ❌ 不符 | 移除跳转项,仅留系统操作 |
| 手柄全程焦点 | 基类已支持,逐面板需核 | ⚠️ 部分 | 各 Tab 内容补 `IFocusable` |
| 护符/装备 | 凹槽模型(本项目自有) | ✅ 按本项目算符合 | 仅作 Tab 收编 |
| 形态技能(魂/魄) | 独立面板(本项目自有) | ✅ 符合 | 作 Tab 收编 |
| 地图形态 | 暗雾/Pin/传送/定位器门控 | ✅ 高度符合 | 仅缺快旅历史(可选) |
| 图鉴 Bestiary | 无 | ❌ 缺失 | 新建面板 + Tab |
---
## 5. 目标信息架构
### 5.1 统一 Tab 屏(`InventoryHubPanel`PanelId.Inventory
Tab 顺序(结合本项目内容,"工具"位由"形态技能"承载):
| # | Tab | 承载面板 | 备注 |
|---|---|---|---|
| 1 | 地图 | `MapPanel` | 由独立面板**收编为 Tab**;地图键直达此 Tab |
| 2 | 形态技能 | `FormSkillPanel` | 三形态 × 魂/魄(本项目核心,取代标杆"工具"位) |
| 3 | 能力 | `DataDrivenAbilityPanel` | 解锁总览 |
| 4 | 护符 | `CharmEquipPanel` | 凹槽装备(收编为 Tab |
| 5 | 物品 | `ItemInventoryPanel` | 收藏/材料/关键道具 |
| 6 | 任务 | `QuestLogPanel` | NPC 任务日志 |
| 7 | 图鉴 | `BestiaryPanel`**新建** | 击杀解锁敌人条目 |
> Tab 数量可裁剪;至少 1/2/4/5 为首发必备3/6/7 视进度排期。
### 5.2 暂停薄覆盖(`DataDrivenPauseMenuController`PanelId.Pause
仅保留系统级动作,**删除一切 `OpenPanel` 查看类跳转**
| 项 | Action |
|---|---|
| 继续 | `Resume` |
| 选项 | `OpenSettings` |
| 返回主菜单 | `ReturnToMainMenu` |
| 退出 | `Quit` |
### 5.3 入口操作契约
| 输入 | 行为 |
|---|---|
| `Inventory` 键 | 打开统一屏(回上次 Tab已开则关闭toggle |
| 地图键(`EVT_MapOpen`/`EVT_FastTravelOpen` | 打开统一屏并选中**地图 Tab** |
| `InventoryTabNext/Prev`L/R 肩键) | 在统一屏内循环 Tab |
| `Pause`Start | 打开暂停薄覆盖(独立,不与统一屏共栈语义) |
| `Cancel`ESC/B | 导航器关栈顶一层(子详情→整屏) |
---
## 6. 改造方案(分阶段)
> 全程走脚手架;改完跑第 8 节验证。
### 阶段 A — 收敛入口职责(低风险,主要是配置)
1. **精简暂停配置** `Assets/_Game/Data/UI/UI_PauseMenuConfig.asset`:删除 `FormSkills/Abilities/Map``OpenPanel` 项,仅留 Resume/Settings/ReturnToMainMenu/Quit。
2. **背包键 toggle**:在 `UIManager``OpenInventory()` 增加 toggle参照现有 `TogglePause()` 模式:栈顶若为 Inventory 则 `Pop`,否则 `OpenPanel`)。
3. **地图键直达地图 Tab**:将 `EVT_MapOpen`/`EVT_FastTravelOpen` 改为"打开 Inventory Hub 并选中地图 Tab"。建议给 `InventoryHubPanel``OpenAtTab(int)` / 增一个 `IntEventChannelSO`(如 `EVT_InventoryOpenAtTab``UIManager.OpenMap()` 打开 Hub 后请求选中地图 Tab。
- 保留 `MapPanel` 独立 PanelId 与否由"地图是否需脱离 Hub 全屏"决定(见第 9 节待决)。
### 阶段 B — 面板收编为 Tab用脚手架重建 Hub 预制件)
4. **扩建 `UI_InventoryHub` 预制件**:用 `InventoryHubScaffoldWizard.ScaffoldInventoryHub`(或现有 Hub 脚手架)把 5.1 的面板逐个挂为 `TabEntry.content`,配 `headerButton` + `headerHighlight`,按 5.1 顺序排列。
- 各 Tab 内容根需实现 `IFocusable`(或保证内部首项可聚焦),以便切 Tab 自动接管焦点。
- 地图 / 护符既有独立 PanelId 的,改为**实例复用**:要么 Tab 内嵌同一面板预制,要么 Hub 内 Tab 与独立 PanelId 指向同一 root二选一避免双实例见待决
5. **Tab 头字形提示**Tab 条左右加 `InputIconImage` / `InputDeviceIconSwitcher`,显示 L/R 肩键字形(随设备切换)。
### 阶段 C — 补图鉴(新面板)
6. **新建 `BestiaryPanel`**:仿 `DataDrivenAbilityPanel` 的数据驱动套路——`BestiaryEntrySO`/数据库 SO 列敌人条目,击杀解锁(订阅敌人死亡事件),网格 + 详情。先补对应 **Editor 脚手架**(参考 `UIAbilityOverviewScaffold``AssignReference` 绑定模式)再建预制件。
7. 注册为第 7 个 Tab数据源接 `Docs/Design/48_EnemyRoster.md` / 敌人数据库。
### 阶段 D — 打磨
8. 进出场动画统一Hub 已有滑入+淡入);暂停覆盖层半透明背板。
9. 逐 Tab 核手柄默认焦点;确认 `Cancel` 在"子详情打开时只退一层"。
---
## 7. 涉及改动清单(速查)
| 类型 | 对象 | 改动 |
|---|---|---|
| 资产 | `UI_PauseMenuConfig.asset` | 删跳转项 |
| 代码 | `UIManager.cs` | `OpenInventory` toggle`OpenMap` 改为开 Hub 定位地图 Tab |
| 代码 | `InventoryHubPanel.cs` | 增 `OpenAtTab(int)` + 监听 `EVT_InventoryOpenAtTab` |
| 事件 | 新增 `EVT_InventoryOpenAtTab`(Int) | 经 `CreateEventChannelAssets` 创建 |
| 预制件 | `UI_InventoryHub` | 经 Hub 脚手架挂全部 Tab + 字形提示 |
| 新建 | `BestiaryPanel` + SO + 脚手架 + 预制件 | 阶段 C |
| 可选 | `PanelId.Bestiary` | 若图鉴也需独立直达 |
---
## 8. 改造后自检(强制)
- `BaseGames/Tools/Validation/Validate All ScriptableObjects`
- `BaseGames/Addressables/Validate Address Keys`(新 SO/预制件地址常量化)
- `BaseGames/Tools/Maintenance/Physics2D Layer Matrix/Check`
- 运行期手测:背包键 toggle、L/R 切 7 个 Tab、地图键直达地图 Tab、暂停覆盖仅系统项、ESC 逐层退、全程手柄可达。
---
## 9. 待决问题
1. **地图双形态**:地图既作 Hub 的 Tab又是否保留可全屏脱离 Hub 的独立打开?(影响是否保留 `PanelId.Map` 双实例策略)
2. **首发 Tab 集**7 个是否全部首发,还是先上 地图/形态技能/护符/物品,能力·任务·图鉴二期?
3. **图鉴数据源**:解锁条件(首次击杀?需击杀 N 次解锁全条目?)与数据归属(敌人数据库 vs 独立 `BestiaryEntrySO`)。
4. **暂停与统一屏的栈关系**:是否允许在暂停覆盖里再开统一屏(一般不允许,二者互斥)。