大于 800×600 分辨率下技能 Tooltip 不显示,以及其余 HUD / 面板悬停提示与视口坐标偏移问题汇总 #557

Closed
opened 2026-10-02 09:37:30 +00:00 by troytt · 0 comments
Owner

问题描述

当视口分辨率切换至 800×600 以上档位(1024×768、1068×600、1280×720)时,鼠标悬停在技能树面板(S/T)或底部快捷技能栏 / 技能弹出面板(Left/Right Skill Slot & Speedbar Popup)上均不会显示技能 Tooltip。

进一步排查全量 UI 组件后发现,除技能 Tooltip 外,其他 HUD 区域、面板悬停提示与全屏覆盖层在大分辨率视口下同样存在坐标未随渲染锚点平移或边界硬编码为 800×600 的问题(关联 #542)。


根因分析与全量 UI 排查清单

1. 技能 Tooltip 不显示 & 层级遮挡(SkillTreePanel + SkillHotkeysHud)

  • 右侧技能树面板(SkillTreePanel):在 HudManager.render() 中按 ctx.translate(rightDockX - 400, panelOffsetY) 绘制(1024×768 偏移 (+224, +84)、1068×600 偏移 (+268, 0)、1280×720 偏移 (+480, +60)),但 HudManager.handleMouseMove() 与 window mousemove 监听未将逻辑坐标转换至右栏局部 400..800, 0..553 坐标系(扩展视口下 marginW = 0),导致 skillTree.handleMouseMove 永远无法命中 415..621 的技能节点,hoveredSkill 恒为 null。
  • 底部左右技能槽与 Speedbar 弹出栏(SkillHotkeysHud):在 HudManager.render() 中按 ctx.translate(barOffsetX, barOffsetY) 绘制(1024×768 偏移 (+112, +168)、1068×600 偏移 (+134, 0)、1280×720 偏移 (+240, +120)),但输入事件直接传入未减除 (barOffsetX, barOffsetY) 的视口坐标,导致 LEFT_SKILL_BOUNDS、RIGHT_SKILL_BOUNDS 与 getPopupCells() 全部脱靶,hoverSkillId 与 hoveredPopupSkill 恒为 null。
  • 渲染 Z-Order 遮挡:在 HudManager.render() 底部栏绘制阶段中,this.hotkeys.draw() 先于 this.belt.draw() 执行,当打开右侧技能弹出栏(Speedbar)或显示技能 Tooltip 时,腰带药水与展开的 4×4 腰带面板会覆盖在技能弹出栏与技能 Tooltip 之上;同时当右侧技能树面板打开且悬停底部技能节点时,技能树 Tooltip 在步骤 2 绘制,可能被后续绘制的底栏法力球或顶部怪物血条遮挡。

2. 底部控制栏、生命/法力球与腰带(ControlBarHud / GlobesHud / BeltHud)

  • controlBar(经验条 Tooltip、耐力条 Tooltip、奔跑/行走切换、迷你面板折叠按钮及 6 个子按钮 Tooltip)、globes(生命/法力球悬停数值显示与点击锁定)、belt(腰带悬停自动展开 4×4 药水栏及左/右键点击)在 handleMouseMove 和 handleHudMouseDown 中均未减去 (barOffsetX, barOffsetY)。

3. 右侧背包与装备栏(InventoryPanel)及物品 Tooltip 边界截断(WorldPanelsHud.drawItemTooltip)

  • inventory 的 handleMouseMove 与 handleClick 未转换至右栏局部坐标 (logicalX - (rightDockX - 400), logicalY - panelOffsetY),导致大于 800×600 时背包格子与身上装备槽悬停无 Tooltip、点击错位。
  • WorldPanelsHud.drawItemTooltip 中 Tooltip 矩形边界夹紧硬编码为 Math.min(800 - boxW - 8, ...) 与 Math.min(600 - boxH - 8, ...),在大分辨率下悬停右侧背包物品时,Tooltip 会被强行向左拉扯到 x <= 800 - boxW - 8,脱离物品所在位置。

4. 左侧停靠面板(CharacterSheetPanel / WorldPanelsHud)

  • 在 1024×768(panelOffsetY = 84)与 1280×720(panelOffsetY = 60)下,左栏面板(人物属性 char、储物箱 stash、赫拉迪克方块 cube、商人 vendor、小站 waypoint、任务 quest、佣兵 merc、雇佣 hire、队伍 party、交易 trade、注入/打孔/个性化 imbue/add_sockets/personalize)的鼠标悬停与点击未减去 panelOffsetY(以及 leftDockX),导致:储物箱/方块/商人物品 Tooltip、方块合成/关闭按钮 Tooltip(hoveredCubeButton)、商人底部功能按钮 Tooltip(hoveredVendorButtonSlot)、小站悬停高亮(hoveredWaypointIdx)及按钮点击全部纵向错位。
  • HudManager.handleMouseMove(logicalX, logicalY)(由 CommandMapper.handlePointerMove 直接调用)缺少左栏物品悬停同步到 inventory.hoveredItem 的逻辑;且 HudManager.render() 步骤 10 在 rightPanel !== 'inv' 时未包含 leftPanel === 'merc' | 'imbue' | 'add_sockets' | 'personalize' 的物品 Tooltip 绘制。

5. 视口级弹窗与全屏覆盖层(NPC 对话菜单、区域进入横幅、死亡遮罩)

  • computeNpcDialogLayout、isPointInNpcMenu 与 drawNpcMenu 将 NPC 交互菜单硬编码夹紧在 800×600 内,当 NPC 位于大视口右侧或下方时菜单位置异常偏移。
  • drawAreaBanner 将区域进入横幅(进入:<区域名>)硬编码绘制在 x = 400,在大分辨率下未居中于 viewportWidth / 2。
  • HudManager.render() 中的死亡覆盖层(isDead)背景矩形硬编码为 fillRect(0, 0, 800, 600) 且文字绘制在 (400, 300),在大分辨率下仅覆盖左上角 800×600 区域。

修复方案

  1. 在 HudManager 中统一通过 toControlBarLocal、toLeftDockLocal、toRightDockLocal、fromLeftDockLocal、fromRightDockLocal 对 handleMouseMove、window mousemove、handleHudMouseDown、isPointInterceptedByHud 进行坐标转换,并消除重复的 mousemove 逻辑。
  2. 调整 HudManager.render() 中底栏与技能树 Tooltip 的绘制顺序:belt.draw() 先于 hotkeys.draw() 执行,并在底栏之后补绘技能树悬停 Tooltip,防止技能弹出栏或技能 Tooltip 被腰带/球体遮挡。
  3. 补全 HudManager.render() 对 merc / imbue / add_sockets / personalize 面板的物品 Tooltip 渲染条件,并将 profile.width、profile.height 传入 drawItemTooltip、computeNpcDialogLayout / drawNpcMenu / isPointInNpcMenu、drawAreaBanner 及死亡覆盖层。
## 问题描述 当视口分辨率切换至 `800×600` 以上档位(`1024×768`、`1068×600`、`1280×720`)时,鼠标悬停在技能树面板(`S`/`T`)或底部快捷技能栏 / 技能弹出面板(`Left/Right Skill Slot` & `Speedbar Popup`)上均不会显示技能 Tooltip。 进一步排查全量 UI 组件后发现,除技能 Tooltip 外,其他 HUD 区域、面板悬停提示与全屏覆盖层在大分辨率视口下同样存在坐标未随渲染锚点平移或边界硬编码为 `800×600` 的问题(关联 #542)。 --- ## 根因分析与全量 UI 排查清单 ### 1. 技能 Tooltip 不显示 & 层级遮挡(`SkillTreePanel` + `SkillHotkeysHud`) - **右侧技能树面板(`SkillTreePanel`)**:在 `HudManager.render()` 中按 `ctx.translate(rightDockX - 400, panelOffsetY)` 绘制(`1024×768` 偏移 `(+224, +84)`、`1068×600` 偏移 `(+268, 0)`、`1280×720` 偏移 `(+480, +60)`),但 `HudManager.handleMouseMove()` 与 `window` `mousemove` 监听未将逻辑坐标转换至右栏局部 `400..800, 0..553` 坐标系(扩展视口下 `marginW = 0`),导致 `skillTree.handleMouseMove` 永远无法命中 `415..621` 的技能节点,`hoveredSkill` 恒为 `null`。 - **底部左右技能槽与 Speedbar 弹出栏(`SkillHotkeysHud`)**:在 `HudManager.render()` 中按 `ctx.translate(barOffsetX, barOffsetY)` 绘制(`1024×768` 偏移 `(+112, +168)`、`1068×600` 偏移 `(+134, 0)`、`1280×720` 偏移 `(+240, +120)`),但输入事件直接传入未减除 `(barOffsetX, barOffsetY)` 的视口坐标,导致 `LEFT_SKILL_BOUNDS`、`RIGHT_SKILL_BOUNDS` 与 `getPopupCells()` 全部脱靶,`hoverSkillId` 与 `hoveredPopupSkill` 恒为 `null`。 - **渲染 Z-Order 遮挡**:在 `HudManager.render()` 底部栏绘制阶段中,`this.hotkeys.draw()` 先于 `this.belt.draw()` 执行,当打开右侧技能弹出栏(Speedbar)或显示技能 Tooltip 时,腰带药水与展开的 `4×4` 腰带面板会覆盖在技能弹出栏与技能 Tooltip 之上;同时当右侧技能树面板打开且悬停底部技能节点时,技能树 Tooltip 在步骤 2 绘制,可能被后续绘制的底栏法力球或顶部怪物血条遮挡。 ### 2. 底部控制栏、生命/法力球与腰带(`ControlBarHud` / `GlobesHud` / `BeltHud`) - `controlBar`(经验条 Tooltip、耐力条 Tooltip、奔跑/行走切换、迷你面板折叠按钮及 6 个子按钮 Tooltip)、`globes`(生命/法力球悬停数值显示与点击锁定)、`belt`(腰带悬停自动展开 `4×4` 药水栏及左/右键点击)在 `handleMouseMove` 和 `handleHudMouseDown` 中均未减去 `(barOffsetX, barOffsetY)`。 ### 3. 右侧背包与装备栏(`InventoryPanel`)及物品 Tooltip 边界截断(`WorldPanelsHud.drawItemTooltip`) - `inventory` 的 `handleMouseMove` 与 `handleClick` 未转换至右栏局部坐标 `(logicalX - (rightDockX - 400), logicalY - panelOffsetY)`,导致大于 `800×600` 时背包格子与身上装备槽悬停无 Tooltip、点击错位。 - `WorldPanelsHud.drawItemTooltip` 中 Tooltip 矩形边界夹紧硬编码为 `Math.min(800 - boxW - 8, ...)` 与 `Math.min(600 - boxH - 8, ...)`,在大分辨率下悬停右侧背包物品时,Tooltip 会被强行向左拉扯到 `x <= 800 - boxW - 8`,脱离物品所在位置。 ### 4. 左侧停靠面板(`CharacterSheetPanel` / `WorldPanelsHud`) - 在 `1024×768`(`panelOffsetY = 84`)与 `1280×720`(`panelOffsetY = 60`)下,左栏面板(人物属性 `char`、储物箱 `stash`、赫拉迪克方块 `cube`、商人 `vendor`、小站 `waypoint`、任务 `quest`、佣兵 `merc`、雇佣 `hire`、队伍 `party`、交易 `trade`、注入/打孔/个性化 `imbue`/`add_sockets`/`personalize`)的鼠标悬停与点击未减去 `panelOffsetY`(以及 `leftDockX`),导致:储物箱/方块/商人物品 Tooltip、方块合成/关闭按钮 Tooltip(`hoveredCubeButton`)、商人底部功能按钮 Tooltip(`hoveredVendorButtonSlot`)、小站悬停高亮(`hoveredWaypointIdx`)及按钮点击全部纵向错位。 - `HudManager.handleMouseMove(logicalX, logicalY)`(由 `CommandMapper.handlePointerMove` 直接调用)缺少左栏物品悬停同步到 `inventory.hoveredItem` 的逻辑;且 `HudManager.render()` 步骤 10 在 `rightPanel !== 'inv'` 时未包含 `leftPanel === 'merc' | 'imbue' | 'add_sockets' | 'personalize'` 的物品 Tooltip 绘制。 ### 5. 视口级弹窗与全屏覆盖层(NPC 对话菜单、区域进入横幅、死亡遮罩) - `computeNpcDialogLayout`、`isPointInNpcMenu` 与 `drawNpcMenu` 将 NPC 交互菜单硬编码夹紧在 `800×600` 内,当 NPC 位于大视口右侧或下方时菜单位置异常偏移。 - `drawAreaBanner` 将区域进入横幅(`进入:<区域名>`)硬编码绘制在 `x = 400`,在大分辨率下未居中于 `viewportWidth / 2`。 - `HudManager.render()` 中的死亡覆盖层(`isDead`)背景矩形硬编码为 `fillRect(0, 0, 800, 600)` 且文字绘制在 `(400, 300)`,在大分辨率下仅覆盖左上角 `800×600` 区域。 --- ## 修复方案 1. 在 `HudManager` 中统一通过 `toControlBarLocal`、`toLeftDockLocal`、`toRightDockLocal`、`fromLeftDockLocal`、`fromRightDockLocal` 对 `handleMouseMove`、`window` `mousemove`、`handleHudMouseDown`、`isPointInterceptedByHud` 进行坐标转换,并消除重复的 `mousemove` 逻辑。 2. 调整 `HudManager.render()` 中底栏与技能树 Tooltip 的绘制顺序:`belt.draw()` 先于 `hotkeys.draw()` 执行,并在底栏之后补绘技能树悬停 Tooltip,防止技能弹出栏或技能 Tooltip 被腰带/球体遮挡。 3. 补全 `HudManager.render()` 对 `merc` / `imbue` / `add_sockets` / `personalize` 面板的物品 Tooltip 渲染条件,并将 `profile.width`、`profile.height` 传入 `drawItemTooltip`、`computeNpcDialogLayout` / `drawNpcMenu` / `isPointInNpcMenu`、`drawAreaBanner` 及死亡覆盖层。
Sign in to join this conversation.
No Label
No Milestone
No project
No Assignees
1 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: troytt/diablo2-web#557
No description provided.