# 移动端 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`、显示遮罩并自动重新进入上次角色,但仍需要在真机和真实服务器上验证网络切换、后台恢复及重连失败边界。低频页面仍需要在真机上做字号、键盘和安全区的视觉微调;当前不能据此视为最终移动端交付完成。