Skip to content

refactor(hud): 引入 measure 阶段并让组件声明背景几何 - #168

Closed
gaoyu06 wants to merge 1 commit into
refactor/hud-settings-and-scalefrom
refactor/hud-measure-pass
Closed

refactor(hud): 引入 measure 阶段并让组件声明背景几何#168
gaoyu06 wants to merge 1 commit into
refactor/hud-settings-and-scalefrom
refactor/hud-measure-pass

Conversation

@gaoyu06

@gaoyu06 gaoyu06 commented Jul 31, 2026

Copy link
Copy Markdown
Member

基于 #167,请先合并那个。

问题

组件的 width/height 一直是在 draw() 内部赋值的,而下列路径全部在 draw() 之前读取它们:

  • 锚点定位 getRealPosition()(RT/RB/CT 分支都用 width/height 算偏移)
  • hover 检测
  • 拖拽边界钳制
  • blur 蒙版

所以所有组件的这些行为都滞后一帧。可观察到的表现:FPS 从 99fps 跳到 100fps 时右对齐组件的右边缘抖一下;进世界第一帧 width 还是 0,右对齐组件闪现在屏幕最右缘。

另一个问题是 blur 蒙版在猜几何:它假设每个组件都是位于 (rX-2, rY)、尺寸 width × height 的单个矩形。这对约三分之二的组件成立,其余要么原点不同(Keystrokes、PotionDisplay),要么画的是多个互不相连的方块(ArmorDisplay)——于是模糊从缝隙里透出来,或整体偏 2px。这是 #164 review 里遗留的那一项。

改动

measure 阶段

新增 Component.measure(),默认空实现所以未迁移的组件保持原状。由 ComponentsManager.measureAll()GlobalListener 每帧开头统一调用一次,早于 blur 蒙版和绘制两个 pass。

背景几何声明

新增 Component.backgroundShape(ShapeSink, originX, originY)drawBlurMask 据此生成蒙版。组件声明什么,蒙版就画什么——不再有猜测空间。

  • Keystrokes 声明每个键位框,并把 spacing 布局计算从 draw() 移到 measure(),使蒙版拿到当帧偏移。键宽抽成 Key.renderWidth()render()backgroundShape() 共用,避免空格键在两处算出不同宽度
  • ArmorDisplay 声明 4 个槽位方块,偏移抽成 slotOffset() 共用。顺带修复该偏移此前未乘 scale——放大 HUD 时槽位会互相重叠

抽出 TextComponent

九个组件重复着逐字符相同的四行(量文字、定高、画框、画字),差异只有字号、padding、框高、文字偏移。改为模板方法后每个降到 3-5 行,并自动获得正确的 measure 时序。

已迁移:FPSDisplay、CPSDisplay、ComboDisplay、ReachDisplay、CoordsDisplay、PingDisplay、ClockDisplay、PlayTime、ServerAddressDisplay。

去掉渲染路径上的配置写入

ClockDisplay/PlayTime/ServerAddressDisplay 各自持有一份逐字符相同的 getLabel(),且都在 draw() 里对设置调用 setValue 写回默认值——那会触发 EventValueChange 进而存盘,位于渲染路径上。统一为 TextComponent.resolveLabel() 并去掉写回:设置为空时每帧重新解析即可,显示结果不变。

其他

  • 补上 CoordsDisplay/PingDisplay 缺失的 mc.thePlayer null 检查(此前直接解引用)
  • TextComponent 在无内容时把尺寸归零,避免留下过期尺寸让蒙版画出一个已经不存在的面板

兼容性

measure() 默认空实现,13 个尚未迁移的组件行为完全不变,可以后续逐个迁移。已迁移组件的字号/padding/框高/文字偏移逐一核对过与原版一致(ComboDisplay 的框高 16、文字偏移 4,Clock/PlayTime/ServerAddress 的 padding 8、偏移 (2,3),其余用基类默认)。

一处刻意的行为修正:文字偏移现在乘 scale,此前不乘,导致放大后文字相对背景框位置偏上。

🤖 Generated with Claude Code

组件的 width/height 一直是在 draw() 内部赋值的,而下列路径全部在 draw() 之前
读取它们:锚点定位(getRealPosition)、hover 检测、拖拽边界钳制、blur 蒙版。
结果是所有组件的这些行为都滞后一帧 —— FPS 从 99fps 跳到 100fps 时右对齐组件的
右边缘会抖,进世界第一帧 width 还是 0,右对齐组件会闪现在屏幕最右缘。

新增 Component.measure()(默认空实现,未迁移的组件保持原状),由
ComponentsManager.measureAll() 在 GlobalListener 每帧开头统一调用一次,
早于 blur 蒙版与绘制两个 pass。

背景几何声明:新增 Component.backgroundShape(ShapeSink, originX, originY),
drawBlurMask 据此生成蒙版而不再猜。此前蒙版假设「每个组件都是位于 (rX-2, rY)、
尺寸 width×height 的单个矩形」,这对约三分之二的组件成立,其余要么原点不同
(Keystrokes、PotionDisplay),要么画的是多个互不相连的方块(ArmorDisplay),
于是模糊会从缝隙里透出来或整体偏 2px。

- Keystrokes 声明每个键位框,并把 spacing 布局计算从 draw() 移到 measure(),
  使蒙版拿到当帧偏移;键宽抽成 Key.renderWidth() 供 render 与 shape 共用,
  避免空格键在两处算出不同宽度
- ArmorDisplay 声明 4 个槽位方块,槽位偏移抽成 slotOffset() 共用。顺带修复
  该偏移此前未乘 scale —— 放大 HUD 时槽位会互相重叠

抽出 TextComponent:九个组件重复着逐字符相同的四行(量文字、定高、画框、画字),
差异只有字号、padding、框高、文字偏移。改为模板方法后每个降到 3-5 行,并自动
获得正确的 measure 时序。已迁移 FPS/CPS/Combo/Reach/Coords/Ping/Clock/PlayTime/
ServerAddress。

其中三个组件各自持有一份逐字符相同的 getLabel(),且都在 draw() 里对设置调用
setValue 写回默认值 —— 那会触发 EventValueChange 进而存盘,位于渲染路径上。
统一为 TextComponent.resolveLabel() 并去掉写回:设置为空时每帧重新解析即可,
显示结果不变。

同时补上几处缺失的 null 检查(CoordsDisplay/PingDisplay 此前直接解引用
mc.thePlayer),并让 TextComponent 在无内容时把尺寸归零,避免留下过期尺寸
让蒙版画出一个已经不存在的面板。

Co-Authored-By: Claude <noreply@anthropic.com>
@gaoyu06

gaoyu06 commented Aug 1, 2026

Copy link
Copy Markdown
Member Author

此 PR 的 base 分支随 #167 合并被删除,GitHub 因此自动关闭了它(而非重定向到 main),且关闭后无法重开。内容原样转至 #172

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant