Skip to content

区段(Sections) ​

自 2.2.11

区段把一个特效的 Timeline 切成几段有名字的部分,每段可以重复、跳转,也可以由游戏代码切换。按住按键才持续的蓄力、直到被驱散才消失的法阵、松手前一直发射的激光,都可以做成同一个特效:开头一段,中间一段长度不定的循环,最后一段收尾。

有三个区段的法阵:Appear、一直重复的 Idle,以及作为 release 区段的 Vanish。

区段怎么播放 ​

  • 区段从你放置的起点开始,到下一个区段的起点为止;最后一个区段一直到内容末尾。
  • 一遍播完时,如果还有剩余的遍数,时钟回到区段起点;最后一遍播完后,按 Then 的设置走。
  • 时钟从一遍的末尾直接跳到下一遍的开头,两者之间的那一刻不会被求值。
  • Timeline 上的所有内容都跟着时钟走。Animation、Activator、Speed、Audio 和 Post Process 片段每一遍都会重新播放;循环区段里的信号每一遍都会触发。
  • 跨过循环接缝、一直开着的 Control 片段会让对象继续运行。见 On Section Loop。
  • 没有区段的 Timeline 播放方式和以前完全一样。

创建区段 ​

快速创建、调整区段起点和重命名。

Sections 行位于标尺下方,Timeline 有了区段之后才会出现。

操作方法
一次建好开始、循环、结束在标尺上右键,选择 Quick create: start / loop / end。只在 Timeline 还没有区段时出现。它会在 0 处加 Start,在内容的三分之一处加一直重复的 Loop,在三分之二处加作为 release 区段的 End。
添加一个区段在标尺上右键选择 Add section here,或者双击 Sections 行的空白处。
调整区段起点拖动色带的左边界。它会吸附到片段边缘、标记、关键帧和播放头;按住 Ctrl 可以自由放置。拖动不会越过相邻的区段。
重命名双击色带,或在它的菜单里选择 Rename...。跳到这个区段的设置和 release 区段会跟着改名。
删除选中色带后按 Delete,或在它的菜单里选择 Remove。

所有编辑都可以撤销。每个区段起点处有一条淡淡的竖线贯穿各条轨道,片段、标记和关键帧也会吸附到区段起点,方便让内容和区段对齐。

区段设置 ​

点击色带会在 Inspector 中显示这个区段;色带的右键菜单里也有同样的设置。

点击色带,在 Inspector 里编辑它的区段。

设置取值含义
Name文本在 Timeline 内唯一。Java 代码和命令都按名字指定区段。
Starttick区段的起点。
RepeatOnce、N times、Forever播放几遍。Forever 会一直重复,直到特效被推进或停止。
ThenCarry on、End、→ 某个区段最后一遍播完后:继续进入下一个区段、在这里结束 Timeline,或者跳到另一个区段。
Release SectionNo、Yes选 Yes 后,停止特效时会播放这个区段。一条 Timeline 最多一个。
TimingAt once、After this passrelease 区段才有:下一个 tick 就进入,或者等当前这一遍播完再进入。

色带上的标记一眼就能看出设置:

标记含义
循环图标一直重复。
×3重复三遍。
■Then 为 End。
→ IdleThen 为跳到 Idle。
琥珀色左边release 区段。
蓝色色带、#2预览当前所在的区段,以及当前是第几遍。
红色色带空区段:和另一个区段起点相同,或者起点在内容末尾之后。运行时会跳过空区段,并在日志里给出警告。

色带的右键菜单里有 Then ▸、Repeat ▸、Set as release section、Copy command、Rename... 和 Remove。Copy command 会复制一条跳到该区段的 /photon fx section 命令。

预览 ​

Timeline 有区段时,传输栏右侧会多出三个按钮,Sections 行会高亮预览当前所在的区段。

按钮作用
Advance当前区段不再重复,这一遍播完后按 Then 走,和游戏里的 advance() 一样。
Release像游戏里调用 destroy(false) 那样停止特效:先播放 release 区段,再让所有内容收尾。
Follow开启(默认):重复和跳转与游戏里一致。关闭:每个区段按时间顺序各播一遍。

开启 Follow 播放预览时,色带菜单里还会出现 Jump here now 和 Jump here after this pass。拖动播放头和跳转时间时,区段一律按时间顺序播放,播放头会停在从头重播应当到达的位置。

Release 区段 ​

如果 Timeline 有 release 区段,destroy(false) 会先播放它,再让所有内容收尾。大多数停止特效的方式调用的都是它:实体死亡、方块变化、/photon fx remove ... false,以及模组代码中不强制的停止。destroy(true) 仍然立即移除一切;没有 release 区段的 Timeline 停止方式和以前完全一样。

播放 release 期间:

  • 特效对它的所有者不再有效(isValid() 为 false),executor 会立刻放手,同一个锚点上可以马上开始新的特效,旧的在一旁播完;
  • 不再接受任何请求;
  • Forever 区段只播一遍;收尾路上再次进入已经播过的区段,Timeline 就此结束,所以 release 一定会结束;
  • 灯光和粒子发光会一直保持,直到残余内容消失。

被停止的特效里的 FX 实例,如果它的源特效有 release 区段,会播放自己的 release 区段。

TIP

让 release 区段的长度固定:Repeat 设为 Once,Then 设为 Carry on 或 End。如果用 release() 而不是 destroy(false) 进入,设为 Forever 的 release 区段会一直循环下去。

游戏内 ​

在聊天栏用命令播放、停止和推进带区段的特效。

命令 ​

text
/photon fx section entity <targets> <action> [fx id]
/photon fx section block <x y z> <action> [fx id]
动作效果
jump <section>从下一个 tick 开始,从该区段的起点播放。
queue <section>当前这一遍播完时改去该区段,衔接无缝。
advance不再重复;这一遍播完后按 Then 走。
release进入 release 区段,按它的 Timing 立即或在这一遍播完后进入。
mcfunction
/photon fx section entity @s jump Vanish
/photon fx section block ~ ~ ~5 advance
/photon fx section entity @e[type=minecraft:zombie,distance=..8] queue "Big Bang" photon:spells/charge

区段名里有空格时要加引号。可选的 fx id 把命令限定到该特效。要停止特效并播放它的 release 区段,使用 /photon fx remove ... false。

Java ​

一道按住按键就持续发射的激光,按住期间什么都不用做:Fire 会一直重复。停止它时会播放 Stop:

java
var executor = new EntityEffectExecutor(fx, level, player, EntityEffectExecutor.AutoRotate.LOOK);
executor.start();

// 松开按键时
executor.getRuntime().destroy(false); // 先播 Stop,再结束

FXRuntime#sections() 返回特效的 SectionControl:

方法含义
hasSections()Timeline 是否有区段。
names()按时间顺序排列的区段名。
current()正在播放的区段;请求了跳转时为跳转目标。在第一个区段之前和结束之后为 null。
pass()当前区段已经播完的遍数。
jumpTo(name)从下一个 tick 开始,从 name 的起点播放。
queue(name)这一遍播完时改去 name。后排的会替换先排的。
advance()不再重复;这一遍播完后按 Then 走。
release()进入 release 区段。和 destroy(false) 不同,特效仍然归你管:可以跳回去,之后再 release。
isReleased() / hasRelease()release 是否进行中或已完成 / Timeline 是否有 release 区段。

这些请求什么都没做时返回 false:区段不存在、Timeline 已经结束或停止、特效正在停止、在第一个区段之前调用 advance(),或者 release() 没有 release 区段可去、已经去过。

只有蓄满才会释放的蓄力攻击:

java
var sections = executor.getRuntime().sections();
if ("Charged".equals(sections.current())) {
    executor.getRuntime().destroy(false); // release 区段:Blast
} else {
    sections.jumpTo("Fizzle");            // 太早松手
}

让特效从某个区段开始,而不是从 0 开始,例如区块重新加载后重建常驻特效,不想再播一次开场:

java
executor.setStartSection("Idle"); // 在 start() 之前设置
executor.start();
// 或者,对自己 emit 的 runtime:
runtime.emit(executor, 0, "Idle");

FX 实例有自己的区段:((FXInstanceObject) runtime.findObject("circle")).sections()。见 FX 实例。

客户端线程

请在客户端线程调用 SectionControl。区段在每个客户端各自运行,不同客户端的切换可能相差一个 tick。

限制 ​

  • 跳转会让动画姿态瞬间改变。用 queue 在一遍结束时切换,或者让前后姿态对齐。
  • Audio 片段按自己的节奏循环,不会跟着区段对齐。
  • setRate(0) 也会冻住 release 区段。
  • /photon fx remove ... true 无法打断已经在播 release 的特效,因为它已经离开了 executor。持有 runtime 的 Java 代码可以调用 destroy(true)。

相关内容 ​

Released under the MIT License.