feat: complete mobile UI implementation
This commit is contained in:
@@ -0,0 +1,656 @@
|
||||
# 移动端 UI 与现有 PC UI 共存实施方案
|
||||
|
||||
## 1. 目标与结论
|
||||
|
||||
本方案用于把横屏移动端 UI 草图落地到现有 Godot 客户端,同时保留当前 PC UI、40250 交互语义、网络协议和玩法逻辑。
|
||||
|
||||
草图入口:[`../.planning/sketches/001-mobile-hud/index.html`](../.planning/sketches/001-mobile-hud/index.html)
|
||||
|
||||
总体结论:
|
||||
|
||||
- 不重写网络、角色、物品、技能、任务、组队和商店数据逻辑。
|
||||
- PC 与移动端共用同一套客户端状态和业务控制器,分别使用不同的 HUD 与窗口布局。
|
||||
- 首页 HUD、虚拟摇杆、技能盘、菜单路由和移动端输入仲裁需要新增。
|
||||
- 高频窗口需要移动端专用布局;低频窗口可先套移动端容器,随后逐步重排。
|
||||
- 服务端或 NPC 上下文驱动的窗口不能被菜单强制打开,菜单只能展示入口条件或导航到对应场景。
|
||||
- 整体属于 UI 层中等偏大改动,但不是客户端重写。预计可复用约 70% 的现有功能逻辑。
|
||||
|
||||
## 2. 已确定的移动端设计规则
|
||||
|
||||
### 2.1 设备与视觉方向
|
||||
|
||||
- 横屏为唯一移动端布局方向。
|
||||
- 设计基准为 844×390,布局必须适配更宽的 Android 屏幕、平板和刘海/挖孔安全区。
|
||||
- 风格采用现代手游半透明 HUD、暗色玻璃、暖铜金边框和低饱和背景。
|
||||
- 不直接复制其他游戏素材,只参考暗黑 ARPG 的信息层级、触控半径和功能收纳方式。
|
||||
|
||||
### 2.2 首页 HUD
|
||||
|
||||
```text
|
||||
┌──────────────────────────────────────────────────────────────┐
|
||||
│ 名称 背包 小地图 菜单 │
|
||||
│ 头像 │
|
||||
│ HP/MP 目标名称与血条 │
|
||||
│ 队员 1 │
|
||||
│ 队员 2 当前任务追踪 │
|
||||
│ │
|
||||
│ 游戏世界 │
|
||||
│ │
|
||||
│ 移动摇杆 技能 / 普攻 │
|
||||
└──────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
固定规则:
|
||||
|
||||
- 玩家名称位于左上头像上方。
|
||||
- HP、MP 和职业资源条位于头像下方,宽度与头像一致。
|
||||
- 点击玩家头像进入角色、装备、技能、坐骑、表情和称号页面。
|
||||
- 角色功能不出现在右上菜单。
|
||||
- 组队后,队员头像、名称、HP 和距离显示在玩家头像下方;未组队时不占空间。
|
||||
- 队伍不出现在社交菜单,也不设置独立按钮。
|
||||
- 右上角从左到右为背包、小地图、菜单;点击小地图打开大地图。
|
||||
- 当前任务条直接打开任务日志,不放入菜单。
|
||||
- 底部中央不设置功能栏,只在左下和右下保留必要战斗控件。
|
||||
|
||||
### 2.3 右上菜单
|
||||
|
||||
菜单只保留五个一级分类:
|
||||
|
||||
| 一级分类 | 二级内容 |
|
||||
|---|---|
|
||||
| 社交 | 聊天、好友、公会、情侣、观战 |
|
||||
| 成长 | 精炼、龙魂、Cube 制作 |
|
||||
| 活动 | 副本、钓鱼 |
|
||||
| 商业 | 商店、商城、交易、私人商店、仓库、兑换 |
|
||||
| 系统 | 系统设置、游戏设置、帮助、选择角色、登出、退出 |
|
||||
|
||||
页面层级最多两层。二级页必须提供返回上一级和关闭两个操作。
|
||||
|
||||
## 3. 当前代码基础
|
||||
|
||||
### 3.1 UI 装配
|
||||
|
||||
`project/game_scene.gd` 已负责创建并连接以下模块:
|
||||
|
||||
- `Hud`
|
||||
- `InventoryUI`
|
||||
- `SkillUI`
|
||||
- `CharStatusUI`
|
||||
- `Quickbar`
|
||||
- `QuestLog`
|
||||
- `PartyUI`
|
||||
- `FriendUI`
|
||||
- `GuildUI`
|
||||
- `LoveUI`
|
||||
- `ShopUI`
|
||||
- `ExchangeUI`
|
||||
- `SafeboxUI`
|
||||
- `MallUI`
|
||||
- `CubeUI`
|
||||
- `RefineUI`
|
||||
- `DragonSoulUI`(当前功能开关关闭)
|
||||
- `Minimap`
|
||||
- `AtlasUI`
|
||||
- `SystemMenuUI`
|
||||
|
||||
这些模块已经连接 `M2Client` 信号并负责现有功能行为。移动端不应复制这一套网络和状态处理。
|
||||
|
||||
### 3.2 现有 HUD 接口可作为兼容协议
|
||||
|
||||
`project/net_play.gd` 通过以下方法更新 `Hud`:
|
||||
|
||||
```gdscript
|
||||
set_vitals(hp, max_hp, sp, max_sp)
|
||||
set_stamina(value, max_value)
|
||||
set_exp(xp, next_xp)
|
||||
set_level(level)
|
||||
set_energy(value, max_value)
|
||||
set_target(name, hp_pct)
|
||||
clear_target()
|
||||
```
|
||||
|
||||
移动端 HUD 实现相同的方法后,可以直接作为 `net_play.setup(..., hud_node)` 的 HUD 参数,无需修改网络更新流程。
|
||||
|
||||
### 3.3 PC 固定布局不能直接缩放成移动端
|
||||
|
||||
当前工程基准分辨率为 1920×1080,`UiManager.screen` 也默认使用该尺寸。`hud.gd` 中状态条锚定左下且 HP 宽度为 240,现有 Python UI 脚本还包含大量固定坐标。
|
||||
|
||||
因此不能把整个 PC CanvasLayer 等比缩小后直接作为最终移动端 UI,否则会出现:
|
||||
|
||||
- 字体和触控目标过小。
|
||||
- 横屏短边空间不足。
|
||||
- 多窗口互相覆盖。
|
||||
- 标题栏拖动、右键、鼠标悬停等 PC 交互无法在触屏完成。
|
||||
- 刘海、圆角和系统手势区遮挡 UI。
|
||||
|
||||
### 3.4 当前触摸能力
|
||||
|
||||
现有代码已经具备:
|
||||
|
||||
- 单指轻点地面移动或选择实体。
|
||||
- 单指拖动旋转镜头。
|
||||
- 双指缩放镜头。
|
||||
- `pointing/emulate_mouse_from_touch=false`,不会把触摸再次模拟成鼠标事件。
|
||||
|
||||
当前已具备:
|
||||
|
||||
- 虚拟摇杆连续移动,以及普攻、药水和 4 个技能触摸按钮。
|
||||
- UI 触点按 index 捕获,摇杆/战斗触点不会被世界点地和镜头误判;窗口打开时由 `UiManager` 阻断世界输入。
|
||||
- 双指世界手势不会生成点地移动;切后台、失焦和恢复时会释放摇杆/攻击状态。
|
||||
- 背包支持点按选择、再次点按使用、点另一格移动;交易、私人商店、仓库和商城支持移动端候选列表或点按操作。
|
||||
|
||||
代码已覆盖:
|
||||
|
||||
- 技能长按瞄准、拖动调整方向和松手释放;短按仍沿用现有目标/自动射程逻辑。
|
||||
- 角色属性/装备、技能、聊天/私聊、系统设置和游戏设置的移动横屏页面。
|
||||
- 物品长按详情与触摸拖放、技能拖入快捷栏、快捷栏槽位交换;无法拖放时仍保留点按替代路径。
|
||||
|
||||
后续主要是 Android/iOS 真机上的 DPI、键盘、手势区和视觉验收。
|
||||
|
||||
### 3.5 现有队伍 UI 可直接演进
|
||||
|
||||
`PartyUI` 已经:
|
||||
|
||||
- 监听 `party_changed` 和生命状态更新。
|
||||
- 队伍为空时自动隐藏。
|
||||
- 显示成员名字、HP、队长和角色状态。
|
||||
- 点击成员可选中对应角色。
|
||||
- 支持角色分配、踢人、经验分配和组队治疗。
|
||||
|
||||
移动端只需要增加紧凑布局模式并更换挂载位置,无需重写队伍逻辑。
|
||||
|
||||
## 4. 目标架构
|
||||
|
||||
```text
|
||||
GameScene
|
||||
├── M2Client / NetPlay / PlayerController / GameCamera
|
||||
│ └── PC 与移动端共享,不复制协议和玩法状态
|
||||
│
|
||||
├── UiManager
|
||||
│ └── 继续管理功能窗口栈、模态遮罩和关闭顺序
|
||||
│
|
||||
├── DesktopUiRoot
|
||||
│ ├── 当前 Hud
|
||||
│ ├── 当前 Quickbar
|
||||
│ └── 当前 PC 窗口布局
|
||||
│
|
||||
└── MobileUiRoot
|
||||
├── MobileHud
|
||||
│ ├── PlayerCard
|
||||
│ ├── PartyHost
|
||||
│ ├── TargetCard
|
||||
│ ├── QuestTracker
|
||||
│ ├── MinimapHost
|
||||
│ └── TopRightActions
|
||||
├── MobileInputOverlay
|
||||
│ ├── VirtualJoystick
|
||||
│ ├── AttackButton
|
||||
│ ├── SkillWheel
|
||||
│ └── ContextAction
|
||||
├── MobileMenuDrawer
|
||||
├── MobileWindowHost
|
||||
└── MobileUiRoot(当前同时承担路由职责)
|
||||
```
|
||||
|
||||
职责边界:
|
||||
|
||||
- `MobileHud` 只显示状态并发出点击信号,不直接发送网络包。
|
||||
- `MobileInputOverlay` 把触控动作转换为现有控制器调用。
|
||||
- `MobileUiRoot` 把头像、背包、小地图、任务和菜单项路由到现有 UI 控制器;后续如路由继续膨胀,再拆出独立 `MobileUiRouter`。
|
||||
- `MobileWindowHost` 负责安全区、全屏面板、返回键和过渡动画。
|
||||
- 原有 UI 控制器继续处理数据、服务器信号和业务动作。
|
||||
|
||||
## 5. UI 模式选择
|
||||
|
||||
新增 `UiProfile`,支持 `AUTO`、`DESKTOP`、`MOBILE` 三种模式。
|
||||
|
||||
自动选择建议:
|
||||
|
||||
```gdscript
|
||||
enum Mode { AUTO, DESKTOP, MOBILE }
|
||||
|
||||
static func resolve(mode: Mode) -> Mode:
|
||||
if mode != Mode.AUTO:
|
||||
return mode
|
||||
return Mode.MOBILE if OS.has_feature("mobile") else Mode.DESKTOP
|
||||
```
|
||||
|
||||
要求:
|
||||
|
||||
- Android 和 iOS 默认移动 UI。
|
||||
- macOS 默认 PC UI。
|
||||
- 桌面开发时允许通过项目设置或启动参数强制移动 UI,便于调试。
|
||||
- 自动判断只在进入游戏时执行,切换 UI 模式需要重建 UI 根节点,避免运行中残留窗口。
|
||||
|
||||
建议新增项目配置:
|
||||
|
||||
```text
|
||||
mt/ui/profile = auto | desktop | mobile
|
||||
mt/ui/mobile_scale = 1.0
|
||||
mt/ui/show_touch_debug = false
|
||||
```
|
||||
|
||||
## 6. 建议文件结构
|
||||
|
||||
```text
|
||||
project/ui/
|
||||
├── mobile/
|
||||
│ ├── mobile_ui_root.gd
|
||||
│ ├── mobile_hud.gd
|
||||
│ ├── mobile_input_overlay.gd
|
||||
│ ├── mobile_menu_drawer.gd
|
||||
│ ├── mobile_ui_router.gd
|
||||
│ ├── mobile_window_host.gd
|
||||
│ └── components/
|
||||
│ ├── player_card.gd
|
||||
│ ├── party_member_strip.gd
|
||||
│ ├── quest_tracker.gd
|
||||
│ ├── virtual_joystick.gd
|
||||
│ ├── skill_button.gd
|
||||
│ └── item_touch_slot.gd
|
||||
├── desktop/
|
||||
│ └── 可后续把当前 HUD 迁入,首期不要求移动文件
|
||||
└── ui_profile.gd
|
||||
```
|
||||
|
||||
首期不要搬动所有现有文件,以减少路径变化和回归风险。
|
||||
|
||||
## 7. 现有功能与移动端入口映射
|
||||
|
||||
### 7.1 首页直达入口
|
||||
|
||||
| 移动端入口 | 现有目标 | 接入方式 | 改动等级 |
|
||||
|---|---|---|---|
|
||||
| 玩家头像 | `CharStatusUI`、`SkillUI` | 头像打开角色容器;容器内调用现有角色/技能状态 | 中 |
|
||||
| 背包 | `InventoryUI.toggle()` | 右上按钮经路由器调用 | 低 |
|
||||
| 小地图 | `AtlasUI.toggle()` | 小地图自身保持显示,点击打开大地图 | 低 |
|
||||
| 当前任务 | `QuestLog.toggle()` | 任务条点击调用;不进入菜单 | 低 |
|
||||
| 队员条 | `PartyUI` | 增加 compact 模式,挂载到玩家头像下 | 中低 |
|
||||
| 普攻 | `NetPlay.set_attack_key()` | 按下设为 true,抬起设为 false | 中 |
|
||||
| 技能 | `Quickbar.activate(slot)` | 技能按钮使用现有槽位和冷却逻辑 | 中 |
|
||||
| 拾取/交互 | `GroundItems`、`NetPlay` | 使用现有拾取、实体选择和场景交互路径 | 中 |
|
||||
|
||||
### 7.2 右上菜单路由
|
||||
|
||||
| 分类 | 功能 | 当前可否直接打开 | 移动端行为 |
|
||||
|---|---|---|---|
|
||||
| 社交 | 聊天 | 可以 | 调用现有聊天日志入口 |
|
||||
| 社交 | 好友 | 可以 | 调用 `FriendUI.toggle()` |
|
||||
| 社交 | 公会 | 可以 | 调用 `GuildUI.toggle()` |
|
||||
| 社交 | 情侣 | 状态驱动 | 展示情侣状态;无关系时显示空状态 |
|
||||
| 社交 | 观战 | 场景状态驱动 | 展示观战说明或当前观战状态 |
|
||||
| 成长 | 精炼 | 服务器询问驱动 | 显示“前往精炼 NPC”,收到 `refine_ask` 后打开窗口 |
|
||||
| 成长 | 龙魂 | 当前禁用 | 在 `ENABLE_DRAGON_SOUL` 开启前隐藏或显示未开放 |
|
||||
| 成长 | Cube 制作 | NPC/服务器驱动 | 导航到制作 NPC;收到 `cube_opened` 后打开 |
|
||||
| 活动 | 副本 | 任务/场景驱动 | 展示目标与导航,不绕过服务端进入条件 |
|
||||
| 活动 | 钓鱼 | 场景驱动 | 展示说明;到达钓点后由情境按钮开始 |
|
||||
| 商业 | NPC 商店 | NPC 驱动 | 导航或提示靠近 NPC,不能本地强制打开 |
|
||||
| 商业 | 商城 | 服务器状态驱动 | 有商城会话时显示内容,否则显示不可用状态 |
|
||||
| 商业 | 玩家交易 | 玩家交互驱动 | 选择附近玩家后发起交易 |
|
||||
| 商业 | 私人商店 | 玩家/摊位驱动 | 点击摊位浏览;自己的商店进入管理模式 |
|
||||
| 商业 | 仓库 | NPC/服务器驱动 | 导航到仓库 NPC,服务器打开后显示 |
|
||||
| 商业 | 兑换 | NPC/任务上下文驱动 | 显示导航,不伪造兑换上下文 |
|
||||
| 系统 | 设置/帮助 | 可以 | 使用移动端全屏设置页或现有控制器适配页 |
|
||||
| 系统 | 选择角色/登出/退出 | 可以 | 二次确认后调用现有系统操作 |
|
||||
|
||||
菜单只是功能入口,不改变原服务端授权条件。
|
||||
|
||||
## 8. HUD 实施细节
|
||||
|
||||
### 8.1 `MobileHud` 兼容接口
|
||||
|
||||
`MobileHud` 实现与当前 `Hud` 相同的状态更新方法,并额外提供以下信号:
|
||||
|
||||
```gdscript
|
||||
signal avatar_pressed
|
||||
signal inventory_pressed
|
||||
signal minimap_pressed
|
||||
signal menu_pressed
|
||||
signal quest_pressed(quest_id: int)
|
||||
signal party_member_pressed(vid: int)
|
||||
signal context_action_pressed(action: String)
|
||||
```
|
||||
|
||||
`GameScene` 根据 UI 模式创建 `Hud` 或 `MobileHud`,并把最终对象继续传给 `NetPlay`。
|
||||
|
||||
### 8.2 避免重复 HUD
|
||||
|
||||
当前 `hud.gd` 自己创建状态条、小地图占位、快捷栏和背包占位,同时 `GameScene` 还创建正式 `Quickbar`、`InventoryUI` 和 `Minimap`。
|
||||
|
||||
移动模式必须明确只有一个拥有者:
|
||||
|
||||
- `MobileHud` 拥有首页状态、目标、任务、顶部按钮和触控布局。
|
||||
- `Quickbar` 继续拥有技能槽数据、冷却和激活逻辑,但其 PC 可视节点在移动模式隐藏。
|
||||
- `InventoryUI` 继续拥有背包数据和动作,但其 PC 入口隐藏。
|
||||
- `Minimap` 继续提供地图数据/绘制能力,移动模式把可视根节点挂入 `MobileHud.MinimapHost` 或增加 compact 布局。
|
||||
|
||||
不能同时显示 PC HUD 和移动 HUD。
|
||||
|
||||
### 8.3 安全区与缩放
|
||||
|
||||
- 根布局使用 Godot anchors,不使用整页固定坐标。
|
||||
- 使用 `DisplayServer.get_display_safe_area()` 获取安全区。
|
||||
- 左上玩家区和右上按钮组至少保留安全区边距。
|
||||
- 基准触控目标不小于 48dp;普攻主按钮建议 80–96dp。
|
||||
- HUD 缩放按短边计算,并设置最小/最大范围,避免平板按钮过大。
|
||||
- 字体单独分级,不跟随 PC 窗口做纯比例缩放。
|
||||
|
||||
## 9. 移动输入方案
|
||||
|
||||
### 9.1 虚拟摇杆
|
||||
|
||||
在 `PlayerController` 中增加移动轴输入,不模拟键盘事件:
|
||||
|
||||
```gdscript
|
||||
var _mobile_axis := Vector2.ZERO
|
||||
|
||||
func set_mobile_axis(axis: Vector2) -> void:
|
||||
_mobile_axis = axis.limit_length(1.0)
|
||||
```
|
||||
|
||||
移动优先级建议:
|
||||
|
||||
```text
|
||||
虚拟摇杆 > PC 键盘 > 点地移动 > 无移动
|
||||
```
|
||||
|
||||
摇杆输入不为零时:
|
||||
|
||||
- 取消当前点地目标 `_is_going`。
|
||||
- 沿用现有相机相对方向、速度、阻挡、Actor 碰撞和动画逻辑。
|
||||
- 摇杆松开后 `_mobile_axis` 清零。
|
||||
- 受击、锁定、移动技能等现有移动门继续生效。
|
||||
|
||||
### 9.2 普攻与技能
|
||||
|
||||
- 普攻按钮按下调用 `NetPlay.set_attack_key(true)`,抬起或触摸取消调用 `false`。
|
||||
- 技能按钮点击调用 `Quickbar.activate(slot)`。
|
||||
- 技能长按进入瞄准态,拖动调整方向,松手调用 `Quickbar.activate_aimed()`;短按仍调用 `Quickbar.activate()`。
|
||||
- 方向计算、技能冷却、不可使用原因和目标选择继续由现有 `Quickbar`/`NetPlay` 处理。
|
||||
- 触摸取消必须清理攻击按下状态,避免切后台后持续攻击。
|
||||
|
||||
### 9.3 触摸仲裁
|
||||
|
||||
当前 `PlayerController` 和 `GameCamera` 都接收 `InputEventScreenTouch/Drag`。新增移动控件后必须防止同一个触点同时操作 UI 和世界。
|
||||
|
||||
建议规则:
|
||||
|
||||
1. `MobileInputOverlay` 在 `_gui_input` 中记录被 UI 捕获的 touch index。
|
||||
2. 被捕获的 index 不传给玩家点地和镜头控制。
|
||||
3. 摇杆、技能、菜单、窗口区域调用 `get_viewport().set_input_as_handled()`。
|
||||
4. 未被捕获的单指仍用于点地/选中或镜头拖动。
|
||||
5. 双指缩放只统计世界区域中的触点。
|
||||
6. 模态窗口打开时阻止所有世界输入。
|
||||
7. 应用暂停、失焦、死亡和过场时强制释放全部触点状态。
|
||||
|
||||
建议把捕获状态集中到一个 `TouchRouter`,不要让每个按钮各自维护全局触点。
|
||||
|
||||
## 10. 功能窗口适配策略
|
||||
|
||||
### 10.1 三种适配级别
|
||||
|
||||
#### A. 直接复用控制器并更换入口
|
||||
|
||||
适用:背包开关、大地图、任务日志、好友、公会、系统菜单。
|
||||
|
||||
首期由 `MobileUiRoot` 调用现有 `toggle/open/close` 方法。
|
||||
|
||||
#### B. 同一控制器增加移动布局
|
||||
|
||||
适用:队伍、快捷栏、小地图、聊天、系统设置。
|
||||
|
||||
保留数据和信号,给 `_build()` 增加 `layout_mode`,分别构建 desktop/mobile 视图。
|
||||
|
||||
#### C. 拆分逻辑和视图
|
||||
|
||||
适用:背包、角色、技能、商店、交易、仓库、Cube 等固定坐标和拖放较重的窗口。
|
||||
|
||||
逐步拆成:
|
||||
|
||||
```text
|
||||
FeatureController:数据、信号、网络操作、校验
|
||||
DesktopFeatureView:现有 PC 布局
|
||||
MobileFeatureView:横屏全屏布局
|
||||
```
|
||||
|
||||
首期允许保留现有控制器,并只在真正重做对应页面时拆分,避免一次性重构全部 UI。
|
||||
|
||||
### 10.2 PC 专属交互的移动替代
|
||||
|
||||
| PC 交互 | 移动端替代 |
|
||||
|---|---|
|
||||
| 鼠标悬停 tooltip | 短按选中、长按详情 |
|
||||
| 右键使用/出售 | 选中后显示主操作按钮 |
|
||||
| 标题栏拖动窗口 | 固定全屏或右侧面板 |
|
||||
| 键盘 I/K/C/N/M | 首页入口或五类菜单 |
|
||||
| 数字键/F1–F4 技能 | 右下技能盘 |
|
||||
| 鼠标拖动物品 | 长按进入拖动,松手落位 |
|
||||
| ESC 关闭 | 系统返回、面板关闭按钮、遮罩点击 |
|
||||
|
||||
## 11. `GameScene` 接入方案
|
||||
|
||||
建议把 UI 创建拆成三个阶段:
|
||||
|
||||
```gdscript
|
||||
func _build_shared_feature_controllers() -> void:
|
||||
# 创建背包、技能、任务、社交、商店等共享控制器
|
||||
|
||||
func _build_desktop_presentation() -> void:
|
||||
# 创建当前 Hud、PC Quickbar、PC 窗口入口
|
||||
|
||||
func _build_mobile_presentation() -> void:
|
||||
# 创建 MobileUiRoot、MobileHud、触控层和移动菜单
|
||||
```
|
||||
|
||||
接入顺序:
|
||||
|
||||
1. 创建 `UiManager` 和共享功能控制器。
|
||||
2. 检测 `UiProfile`。
|
||||
3. 创建 Desktop 或 Mobile 表现层。
|
||||
4. 把当前 HUD 实例传给 `NetPlay`。
|
||||
5. 将 `Quickbar`、`PlayerController`、`GameCamera`、`GroundItems` 注入 `MobileInputOverlay`。
|
||||
6. 将现有功能控制器注入 `MobileUiRoot` 的路由绑定。
|
||||
7. 地图切换或世界重载时,只重载世界相关 HUD 数据,不重建所有功能控制器。
|
||||
|
||||
## 12. 开发阶段
|
||||
|
||||
### 阶段 M1:双 UI 骨架(已完成,待真机验收)
|
||||
|
||||
目标:PC UI 完全不变,桌面可强制预览移动 UI。
|
||||
|
||||
- 增加 `UiProfile`。
|
||||
- 增加 `MobileUiRoot`、安全区和横屏约束。
|
||||
- `GameScene` 能在 Desktop/Mobile 表现层之间选择。
|
||||
- 移动 HUD 使用假数据完成布局,但不重复显示 PC HUD。
|
||||
|
||||
验收:
|
||||
|
||||
- macOS 默认仍显示现有 PC UI。
|
||||
- 强制 mobile 时只显示移动 HUD。
|
||||
- Android/iOS 自动选择移动 UI。
|
||||
|
||||
### 阶段 M2:首页状态与入口(已完成,待真机验收)
|
||||
|
||||
- 接入玩家名称、HP、MP、资源、经验、等级和状态效果。
|
||||
- 接入目标名称与目标 HP。
|
||||
- 接入背包、小地图、头像、任务条和五类菜单。
|
||||
- 接入左上队伍紧凑条。
|
||||
- 接入死亡、重连、副本目标等覆盖状态。
|
||||
|
||||
验收:所有首页入口打开正确功能,返回后恢复场景输入。
|
||||
|
||||
### 阶段 M3:移动与战斗触控(代码完成,待真机验收)
|
||||
|
||||
- 新增虚拟摇杆连续移动。
|
||||
- 新增普攻、技能、药水和情境交互按钮。
|
||||
- 处理触摸 index 捕获、取消、切后台和模态窗口。
|
||||
- 接入技能冷却、不可使用原因和目标选择反馈。
|
||||
|
||||
验收:移动、镜头、攻击、技能可同时使用且不串触摸。
|
||||
|
||||
### 阶段 M4:高频功能页(部分完成)
|
||||
|
||||
- 角色/装备/技能全屏页:角色属性/装备、技能分类和技能升级已有横屏专用布局;角色表情也提供移动触控页。
|
||||
- 背包和物品详情:背包点按操作、长按详情、数字键盘数量输入、跨窗口长按拖放已完成;仍需真机确认系统手势区和键盘共存体验。
|
||||
- 任务日志和大地图:已有移动托管;大地图支持单指拖动并在双指时冻结单指拖动。
|
||||
- 聊天与好友:聊天/私聊已有横屏输入页、触控按钮和弹窗返回处理,真机键盘体验待验收。
|
||||
|
||||
验收:不依赖右键、鼠标悬停和键盘即可完成完整操作。
|
||||
|
||||
### 阶段 M5:商业、制作与系统(部分完成)
|
||||
|
||||
- 商店、商城、交易、私人商店、仓库和兑换:移动端入口/候选列表/点按操作已覆盖;服务端上下文仍需联机验收。
|
||||
- Cube、精炼、龙魂入口状态:Cube 配方/材料/制作和精炼按钮已有横屏触控布局,龙魂仍按功能开关控制。
|
||||
- 系统设置、游戏设置、帮助、角色切换、登出和退出:系统设置/游戏设置/帮助已有横屏专用布局;系统菜单增加移动端专用横屏入口,好友、公会创建、公会邀请、商城/仓库密码、商店确认等确认弹窗已扩大触控尺寸并接入返回处理。
|
||||
- 确保所有上下文窗口只在服务端允许时打开。
|
||||
|
||||
### 阶段 M6:真机验收与视觉统一(未完成)
|
||||
|
||||
- Android 和 iOS 安全区。
|
||||
- 不同屏幕比例、分辨率和 DPI。
|
||||
- 多指触控、后台恢复和断线重连(代码已接入,仍需真机/联机验收)。
|
||||
- GPU/CPU/内存与触控延迟。
|
||||
- 统一暗色玻璃、铜金边框、字号、按钮和动画。
|
||||
|
||||
## 13. 测试方案
|
||||
|
||||
### 13.1 自动化测试(已实现)
|
||||
|
||||
以下移动端专项测试已经加入项目,并与现有 PC/业务测试一起运行:
|
||||
|
||||
- `mobile_ui_test.gd`:模式解析、横屏保护、安全区、HUD 状态、菜单分类和 UI/世界触点仲裁。
|
||||
- `mobile_window_host_test.gd`:返回键、模态阻断和窗口栈。
|
||||
- `mobile_gesture_test.gd`:长按/拖动触摸状态、技能瞄准、技能拖入快捷栏、快捷栏交换和物品触摸拖放。
|
||||
- `chat_mobile_ui_test.gd`:横屏聊天日志、频道切换、私聊目标和数字键盘友好的输入页。
|
||||
- `gamescene_test.gd`:PC/移动 UI 装配互斥和移动根节点接线。
|
||||
- `char_status_ui_test.gd`、`inventory_ui_test.gd`:角色页、背包详情、数量输入和触摸操作。
|
||||
- `p8_test.gd`:交易候选列表、仓库取出和移动端仓库存入候选列表。
|
||||
- `shop_cube_mall_test.gd`:Cube 配方、材料添加/删除、制作按钮和移动端横屏布局。
|
||||
- `guild_creation_ui_test.gd`、`guild_war_skill_test.gd`、`help_ui_test.gd`:公会、帮助和确认弹窗的移动布局。
|
||||
- `system_menu_ui_test.gd`、`system_option_ui_test.gd`、`private_shop_ui_test.gd`:系统入口、设置和商业窗口的移动交互。
|
||||
|
||||
完整测试集当前共 78 个 `*_test.gd`,现有 PC UI、业务、网络、战斗和移动端测试均通过。推荐命令:
|
||||
|
||||
```bash
|
||||
for test in $(rg --files project -g '*test.gd' | sort); do
|
||||
/opt/homebrew/bin/godot --headless \
|
||||
--rendering-method gl_compatibility \
|
||||
--rendering-driver opengl3 \
|
||||
--audio-driver Dummy \
|
||||
--log-file "/tmp/mtgodot-${test##*/}.log" \
|
||||
--path project --script "${test#project/}" || exit 1
|
||||
done
|
||||
```
|
||||
|
||||
### 13.2 桌面模拟验收
|
||||
|
||||
- 844×390、16:9 平板、超宽屏三档。
|
||||
- 鼠标模拟触控验证所有移动入口。
|
||||
- 强制 mobile profile 后走完登录、角色选择和游戏内 UI。
|
||||
- 同一进程切换地图、死亡复活和断线重连。
|
||||
|
||||
### 13.3 Android/iOS 真机验收
|
||||
|
||||
- 刘海和系统手势区不遮挡按钮。
|
||||
- 左手持续移动时,右手可选目标、普攻和连续释放技能。
|
||||
- 两指缩放不会触发点地或技能。
|
||||
- 拖动物品时不会移动角色或旋转镜头。
|
||||
- 来电/切后台后,摇杆和普攻状态正确释放。
|
||||
- 队伍成员变化、HP 和距离能实时更新。
|
||||
- 商店、仓库、制作等页面不会绕过服务器上下文。
|
||||
|
||||
## 14. 完成标准
|
||||
|
||||
移动端 UI 可认为完成,必须同时满足:
|
||||
|
||||
1. PC UI 默认行为和快捷键无回归。
|
||||
2. Android/iOS 自动进入移动 UI,桌面可强制预览。
|
||||
3. 首页严格符合已确认草图布局。
|
||||
4. 角色只从玩家头像进入。
|
||||
5. 队伍只在头像下方显示,不在社交菜单出现。
|
||||
6. 任务、小地图和背包保持首页直达。
|
||||
7. 右上菜单只有社交、成长、活动、商业、系统五类。
|
||||
8. 不使用键盘、鼠标右键或悬停,也能完成所有移动端操作。
|
||||
9. 所有功能继续使用现有服务器授权和网络包流程。
|
||||
10. 自动化测试、桌面模拟和 Android/iOS 真机测试均通过。
|
||||
|
||||
## 15. 改动规模与主要风险
|
||||
|
||||
### 15.1 改动规模
|
||||
|
||||
| 层级 | 改动规模 | 说明 |
|
||||
|---|---|---|
|
||||
| 网络协议与服务端 | 小/无 | 继续使用现有 `M2Client` 与 40250 流程 |
|
||||
| 游戏状态与战斗逻辑 | 小 | 增加移动输入入口,不重写校验和攻击流程 |
|
||||
| 首页 HUD | 大 | 新建移动端表现层 |
|
||||
| 输入系统 | 中到大 | 摇杆、技能盘、多指仲裁是核心新增 |
|
||||
| 高频功能页 | 中到大 | 背包、角色、技能、任务需重排 |
|
||||
| 低频窗口 | 中 | 可分阶段适配 |
|
||||
| PC UI | 小 | 原样保留,只增加模式分流 |
|
||||
|
||||
### 15.2 主要风险
|
||||
|
||||
1. **触摸穿透**:技能或摇杆触摸同时触发地面移动/镜头。
|
||||
- 对策:集中式 `TouchRouter`,按 touch index 捕获。
|
||||
2. **重复 HUD**:旧 HUD、Quickbar、Minimap 与新 HUD 同时显示。
|
||||
- 对策:明确 Desktop/Mobile 表现层互斥创建。
|
||||
3. **固定坐标窗口过小**:PC Python UI 在移动端不可操作。
|
||||
- 对策:高频页优先重排,低频页先用安全区容器过渡。
|
||||
4. **菜单绕过上下文**:直接打开商店、仓库、精炼等造成无效状态。
|
||||
- 对策:`MobileUiRoot` 区分“可直接打开”和“需要 NPC/服务器状态”。
|
||||
5. **PC 回归**:共享控制器重构影响键盘和鼠标行为。
|
||||
- 对策:首期新增并行表现层,拆分控制器时补双端测试。
|
||||
6. **横屏安全区差异**:按钮被刘海或系统边缘手势遮挡。
|
||||
- 对策:运行时读取安全区并保留可配置边距。
|
||||
|
||||
## 16. 推荐首个实现切片
|
||||
|
||||
首个可真机验证的垂直切片已经完成,当前作为移动端联调基线:
|
||||
|
||||
```text
|
||||
UI 模式选择
|
||||
→ 移动 HUD
|
||||
→ 头像/背包/地图/任务/菜单入口
|
||||
→ 左上队伍条
|
||||
→ 虚拟摇杆
|
||||
→ 普攻 + 4 个技能
|
||||
→ Android 真机战斗验证
|
||||
```
|
||||
|
||||
该切片已让客户端具备可用的移动端首页和核心战斗能力;角色、背包、技能等全屏页也已按使用频率完成移动布局,剩余工作集中在真机/联机验收和视觉微调。
|
||||
|
||||
## 17. 当前实现状态
|
||||
|
||||
截至 2026-09-04,代码已完成首个垂直切片,并继续补齐了部分商业/制作页面:
|
||||
|
||||
- `project/ui/ui_profile.gd`:`AUTO/DESKTOP/MOBILE` 模式选择,支持移动设备自动识别、`mt/ui/profile` 配置和 `--mobile-ui` / `--desktop-ui` 预览参数。
|
||||
- `project/ui/mobile/mobile_ui_root.gd`:移动端 CanvasLayer 根节点,按 844×390 横屏设计基准自适应缩放并处理功能路由。
|
||||
- `project/ui/mobile/mobile_hud.gd`:名称、头像、同宽 HP/MP、目标、队伍紧凑条、任务入口、背包/小地图/菜单入口。
|
||||
- `project/ui/mobile/mobile_input_overlay.gd`、`virtual_joystick.gd`、`mobile_touch_button.gd`:虚拟摇杆、普攻、药水、4 个技能触控按钮、触摸取消和失焦释放。
|
||||
- `project/ui/mobile/mobile_input_overlay.gd`、`project/player_controller.gd`:集中记录移动 UI 触点,避免“摇杆 + 世界触点”触发点地移动。
|
||||
- `project/ui/mobile/mobile_menu_drawer.gd`:社交、成长、活动、商业、系统五类两级菜单。
|
||||
- `project/player_controller.gd`:新增移动轴输入,沿用现有相机相对移动、阻挡、动画和状态门。
|
||||
- `project/ui/char_status_ui.gd`:角色属性/装备和表情移动横屏页面,属性点仍走原 `/stat` 命令。
|
||||
- `project/ui/skill_ui.gd`、`project/ui/quickbar.gd`:技能移动横屏列表、升级和一键放入快捷栏空位。
|
||||
- `project/ui/inventory_ui.gd`:物品长按详情、使用/选择操作和移动端数字键盘数量输入。
|
||||
- `project/ui/chat_ui.gd`:横屏聊天日志、频道切换和私聊输入页。
|
||||
- `project/ui/system_option_ui.gd`、`project/ui/game_option_ui.gd`:横屏系统/游戏设置页,保留原配置和服务器命令。
|
||||
- `project/ui/help_ui.gd`、`project/ui/system_menu_ui.gd`:横屏帮助页和移动模式下的帮助路由。
|
||||
- `project/ui/minimap.gd`:复用现有小地图绘制和数据,移动模式挂载到右上 HUD;点击地图仍打开大地图。
|
||||
- `project/ui/party_ui.gd`、`quickbar.gd`、`quest_log.gd`:移动模式隐藏 PC 表现层,保留原数据和业务控制器。
|
||||
- `project/game_scene.gd`:PC/移动表现层互斥装配,移动端控制器注入统一路由;PC HUD 默认路径保持不变。
|
||||
- `project/ui/safebox_ui.gd`:移动端背包候选列表,点按存入、点按取出和重复请求保护。
|
||||
- `project/ui/cube_ui.gd`:移动端横屏双列滚动布局,配方、材料添加/删除和制作按钮均可触摸。
|
||||
- `project/ui/refine_ui.gd`:移动端横屏精炼信息与操作布局。
|
||||
- `project/ui/guild_ui.gd`:移动端横屏公会四页布局、成员/技能/公会战/公告的触控按钮和创建公会弹窗。
|
||||
- `project/ui/system_menu_ui.gd`:保留桌面原始系统菜单,移动端使用横屏专用系统菜单,入口和服务器命令保持一致。
|
||||
- `project/ui/friend_ui.gd`、`project/game_scene.gd`、`project/ui/shop_ui.gd`、`project/ui/mall_ui.gd`、`project/ui/safebox_ui.gd`:确认弹窗移动触控尺寸与 Android 返回优先取消处理。
|
||||
- `project/ui/ui_manager.gd`、`project/ui/mobile/mobile_window_host.gd`:动态 Button 触摸桥接、原生确认弹窗登记、模态阻断、返回顺序和安全区变化重排。
|
||||
- `project/ui/reconnect_ui.gd`、`project/app_flow.gd`:游戏内断线保留 `GameScene`,显示移动重连遮罩,自动重新进入上次角色。
|
||||
- `project/project.godot`:增加移动 UI 配置项和横屏方向设置。
|
||||
|
||||
当前验证结果:
|
||||
|
||||
- 全部 78 个 `*_test.gd` 通过,包括 `app_flow_lifecycle_test.gd`、`p10_test.gd`、`mobile_ui_test.gd`、`mobile_window_host_test.gd` 和 `mobile_gesture_test.gd`;Godot 脚本解析检查通过。
|
||||
|
||||
尚未完成的部分包括:Android/iOS 真机安全区、不同屏幕比例、多指、后台恢复、性能与触控延迟验收,以及商业页面在真实服务器上下文下的联机验收。断线重连的代码路径已经完成:游戏中断线会保留当前 `GameScene`、显示遮罩并自动重新进入上次角色,但仍需要在真机和真实服务器上验证网络切换、后台恢复及重连失败边界。低频页面仍需要在真机上做字号、键盘和安全区的视觉微调;当前不能据此视为最终移动端交付完成。
|
||||
Reference in New Issue
Block a user