区段(Sections)
自 2.2.11区段把一个特效的 Timeline 切成几段有名字的部分,每段可以重复、跳转,也可以由游戏代码切换。按住按键才持续的蓄力、直到被驱散才消失的法阵、松手前一直发射的激光,都可以做成同一个特效:开头一段,中间一段长度不定的循环,最后一段收尾。
区段怎么播放
- 区段从你放置的起点开始,到下一个区段的起点为止;最后一个区段一直到内容末尾。
- 一遍播完时,如果还有剩余的遍数,时钟回到区段起点;最后一遍播完后,按 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 里编辑它的区段。
| 设置 | 取值 | 含义 |
|---|---|---|
| Name | 文本 | 在 Timeline 内唯一。Java 代码和命令都按名字指定区段。 |
| Start | tick | 区段的起点。 |
| Repeat | Once、N times、Forever | 播放几遍。Forever 会一直重复,直到特效被推进或停止。 |
| Then | Carry on、End、→ 某个区段 | 最后一遍播完后:继续进入下一个区段、在这里结束 Timeline,或者跳到另一个区段。 |
| Release Section | No、Yes | 选 Yes 后,停止特效时会播放这个区段。一条 Timeline 最多一个。 |
| Timing | At once、After this pass | release 区段才有:下一个 tick 就进入,或者等当前这一遍播完再进入。 |
色带上的标记一眼就能看出设置:
| 标记 | 含义 |
|---|---|
| 循环图标 | 一直重复。 |
×3 | 重复三遍。 |
■ | Then 为 End。 |
→ Idle | Then 为跳到 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 区段会一直循环下去。
游戏内
命令
/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 立即或在这一遍播完后进入。 |
/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:
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 区段可去、已经去过。
只有蓄满才会释放的蓄力攻击:
var sections = executor.getRuntime().sections();
if ("Charged".equals(sections.current())) {
executor.getRuntime().destroy(false); // release 区段:Blast
} else {
sections.jumpTo("Fizzle"); // 太早松手
}让特效从某个区段开始,而不是从 0 开始,例如区块重新加载后重建常驻特效,不想再播一次开场:
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)。
相关内容
- On Exit 和 On Section Loop 决定 Control 片段在结束时、以及区段循环时如何处理对象。
- Lifetime Mode 可以做出一直循环、直到发射器被停止的粒子。
- FXRuntime 生命周期 介绍
emit、destroy和状态查询。