拨号序列

拨出一个地址后,星门的 7 个雪佛龙会依次旋转到位,每个雪佛龙对准地址中对应的那一位符号。本文状态机、角度与时长全部取自 TileStargateController.java(DialPhase 枚举、CHEVRON_ANGLES、SYMBOL_STEP、updateEntity()、startSpinToSymbol())与 RenderStargateTESR.java。

基本信息

属性 值
类型 特殊机制(连接动画状态机)
触发条件 在 拨号装置 界面点击拨号按钮,调用 controller.dialOut(dialingAddress)
状态数 4(IDLE / SPINNING / LOCKED / CONNECTED)
雪佛龙数 7(= CHEVRON_ANGLES 数组长度 = 地址位数)

状态机

   IDLE ──dialOut()──► SPINNING ──动画完成──► LOCKED ──停 25 tick──► ┐
     ▲                   ▲                                          │
     │                   └──────── 下一个符号 ──────────────────────┤
     │                                                              │
     │                                            addressIndex ≥ 7 ─┘
     │                                                              ▼
     └──────────────────────────────────────────────────────  CONNECTED
状态 进入条件 行为 退出条件
IDLE 初始值;或 dialed 被置回 false 后区块重载 无动画 dialOut() 成功
SPINNING startSpinToSymbol() 按 smootherStep 缓动转动外环 t ≥ 1(经过 animTotalTicks tick)
LOCKED 一次旋转完成 每个符号静止停顿 lockTicksRemaining 减到 0
CONNECTED addressIndex >= dialAddress.length(7) 传送已就绪,不再有动画 无退出路径

角度计算

常量 值 含义
SYMBOL_STEP 360f / 16 = 22.5° 相邻符号之间的角步进
CHEVRON_ANGLES[7] {308.57, 257.14, 205.71, 154.29, 102.86, 51.43, 0} 7 个雪佛龙各自的基准角,间隔 51.43°(= 360°/7)

目标角度:

targetRotationFor(addressIndex, chevronIndex)
    = CHEVRON_ANGLES[chevronIndex] + addressIndex × 22.5°

其中 addressIndex 是目标地址中该符号的数值(0–15),chevronIndex 是雪佛龙序号(0–6)。所以雪佛龙 0 转到 308.57° + 符号值 × 22.5°,雪佛龙 6 转到 0° + 符号值 × 22.5°,以此类推。

shortestDelta(from, to) 把角度差归一化到 (−180°, 180°],总是走较短弧;角度差超过 180° 时反向旋转。

动画参数

参数 值 来源
每符号最短旋转时长 20 tick(1 秒) animTotalTicks = Math.max(20, (int)(Math.abs(animDelta) / 3f))
常规转速 3°/tick 上式的除数 3f
每符号锁定停顿 25 tick lockTicksRemaining = 25
缓动函数 smootherStep:6t⁵ − 15t⁴ + 10t³ smootherStep()
插值 prev + (cur − prev) × partialTicks RenderStargateTESR

因为时长下限是 20 tick,转动幅度小于 60°(20 × 3)时也会被钳制到 20 tick,所以每个符号的耗时下限固定。

完整耗时

7 个雪佛龙依次锁定,每一步 = 旋转(≥20 tick)+ 停顿(25 tick):

  • 最快:7 × (20 + 25) = 315 tick ≈ 15.75 秒(每个符号都取最短旋转)
  • 最慢:取决于符号序列与雪佛龙基准角的角度差,公式为 Σ max(20, |Δi| / 3) + 7 × 25,最大单步 180° → 60 tick,故上界 7 × (60 + 25) = 595 tick ≈ 29.75 秒

[!WARNING] 传送在动画开始时就已经可用,而不是在 CONNECTED 之后。 dialOut() 成功时立刻把 dialing 设为目标坐标,而 BlockFormedGate.addCollisionBoxesToList() 只检查 controller.isTransmitting()(即 dialing != null),不检查 dialPhase。因此雪佛龙还在转动时走进门就会被传送走。CONNECTED 状态没有任何功能性作用,纯粹是动画的终态标记。

拨号的前置检查

dialOut(int[] sigils) 依次执行 4 项检查,任何一项失败都返回 false 且不产生任何动画:

顺序 检查 失败含义
1 if (dialed) return false; 本星门已经是别的星门的拨入目标
2 if (sga.equals(address)) return false; 目标地址与自身地址相同(不能拨自己)
3 StargateRegistry.INSTANCE.lookup(sga) == null → false 目标地址未注册(全服不存在该地址的星门)
4 !gate.getDialed(address) → false 目标星门拒绝被拨入

第 4 步的 getDialed() 恒返回 true,其唯一作用是把目标星门的 dialed 标志置为 true。该标志在全类中没有任何复位点,所以目标星门一生只能被拨通一次;第四次检查实际上永远通过不了。dialed 不写入 NBT,区块卸载重载后会恢复为 false。

渲染

RenderStargateTESR 分两次绘制 OBJ 模型:

  1. 整体平移到 (x+0.5, y+2.5, z+0.5),按 facing 绕 Y 轴旋转(北 90° / 南 −90° / 西 180°),renderOnly("static") 画固定部分。
  2. 再绕 X 轴旋转 ringAngle(即插值后的 ringRotation),renderOnly("spinners") 画旋转的外环。

模型 stargatenh:models/stargate.obj,贴图 stargatenh:textures/models/stargate.png。

相关条目