屏幕指引箭头

标记一个节点后,屏幕上的方向箭头 HUD 叠加层。只在玩家头戴「眼镜类」护甲时渲染。

实现

src/main/java/com/dyonovan/tcnodetracker/gui/GuiPointer.java,类 GuiPointer extends Gui, 在 TCNodeTracker.postInit(TCNodeTracker.java:79-81)注册到 MinecraftForge.EVENT_BUS。

渲染条件(GuiPointer.java:41-49)

监听 RenderGameOverlayEvent,四道门槛全过才画:

条件 源码 含义
!event.isCancelable() :41 必须是可取消的那类叠加事件
event.type == ElementType.EXPERIENCE :41 画在原版经验条这一层
TCNodeTracker.doGui :42 已在节点列表界面里点过 Mark
头盔槽非空 :43 armorItemInSlot(3)
头盔是 IGoggles :47 thaumcraft.api.IGoggles,接口判定,不是物品判定

doGui 由节点列表界面的 Mark 按钮置 true、关闭时置 false (gui/GuiMain.java:131-134、:172)。

方向计算(GuiPointer.java:51-55)

double direction = (Math.toDegrees(
        Math.atan2(TCNodeTracker.xMarker - this.mc.thePlayer.posX,
                   TCNodeTracker.zMarker - this.mc.thePlayer.posZ)))
        + this.mc.thePlayer.rotationYaw;

即屏幕空间方位角 = 目标相对玩家的 atan2 角 + 玩家 yaw,随后 GL11.glRotatef((float) -direction, 0, 0, 1) 旋转贴图四边形(GuiPointer.java:65)。 箭头只在水平面内旋转,不做俯仰,所以上下关系靠文字而非箭头角度表达。

⚠️ 不检查维度:xMarker / yMarker / zMarker 是全局静态字段,跨维度标记时箭头方向无意义。 Navigator 加载时,跨维度会走地图而不是这个 HUD。

距离与高低文字(GuiPointer.java:78-83)

int distancePL = (int) Math.round(
        this.mc.thePlayer.getDistance(TCNodeTracker.xMarker, mc.thePlayer.posY, TCNodeTracker.zMarker));
String dirY = mc.thePlayer.posY > TCNodeTracker.yMarker ? "…Below"
        : mc.thePlayer.posY == TCNodeTracker.yMarker ? "…Level" : "…Above";
String blocks = Integer.toString(distancePL) + " Blocks";

⚠️ 距离用的是 posY 而不是 yMarker:传入 getDistance 的是 (xMarker, thePlayer.posY, zMarker), Y 分量取的是玩家自己的 Y,所以算出来的是水平距离,不是三维直线距离。 高低由 posY 与 yMarker 的比较单独用文字表达。

文字格式为 <距离> Blocks - <Above|Level|Below>(GuiPointer.java:95), 语言键为 str.blocks.name / str.above.name / str.level.name / str.below.name。

贴图与变换

项 值 源码
贴图(默认) tcnodetracker:textures/gui/arrow.png :24
贴图(备用) tcnodetracker:textures/gui/arrow2.png :25
贴图选择 ConfigHandler.altArrow 为假取默认,否则取备用 :57-58
几何尺寸 64 × 64 像素 :38-39
锚点 width/2 + arrowX、arrowHeight/2 + 5 + arrowY :64
缩放 ConfigHandler.arrowSize 同时作用于箭头和下方文字 :66、:92
绘制方式 Tessellator 手写四边形 + addVertexWithUV :69-75

缩放锚点是先 glTranslated 到锚点、再 glScaled、最后 glTranslatef(-w/2, -h/2, 0) 回原点, 所以缩放围绕箭头中心而非屏幕中心。

已知问题

GuiPointer.java:84 计算了一个颜色变量:

int color = dirY.equals("Below") ? Constants.RED : dirY.equals("Level") ? Constants.WHITE : Constants.GREEN;

这个 color 从未被使用。 实际绘制文字时传的是 Constants.WHITE(:95)。 即「目标在下方显示红色」这个设计没有落地,下方/同层/上方三种情况在屏幕上文字颜色完全一致。

对比 GuiMain.drawScreen(gui/GuiMain.java:384-388)里颜色确实被用上了(当前标记行显示绿色 0x26AA30), 所以更像是 GuiPointer 遗漏而非有意的统一。

另外 dirY 是本地化后的字符串,却被拿去和英文字面量 "Below" / "Level" 比较(:84)。 str.below.name / str.level.name 在三个语言文件里都被翻译了:

$ grep -E "str\.(below|level)\.name" src/main/resources/assets/tcnodetracker/lang/*.lang
en_US.lang:str.level.name=Level
en_US.lang:str.below.name=Below
es_ES.lang:str.level.name=Nivel 
es_ES.lang:str.below.name=Por debajo
zh_CN.lang:str.level.name=级别
zh_CN.lang:str.below.name=你的下方

所以只有在英文语言环境下这两个分支才可能为真;中文 / 西班牙语下恒取 Constants.GREEN。

相关条目

  • 配置项 - arrowX / arrowY / altArrow / arrowSize 的完整说明
  • 节点列表界面 - Mark / Clear Arrow 按钮如何控制 doGui 与标记坐标