动画控制器
约 2033 字大约 7 分钟
2025-01-28
过去什么条件下播放什么动画完全是硬编码的,美术没法自定义。
2.3.0 版本添加了基岩版动画控制器,可以通过控制器自定义动画的播放条件。
控制器写法
只需要在 ysm.json 文件内添加 animation_controllers 字段即可,案例如下:
"files": {
"player": {
"model": {
"main": "models/main.json",
"arm": "models/arm.json"
},
"animation": {
"main": "animations/main.animation.json",
"parcool": "animations/parcool.animation.json"
},
// 可以添加多个文件
"animation_controllers": [
"controller/随便起名字都行啊.json"
],
"texture": [
"textures/texture.png"
]
}
}动画控制器文件里可以包含多个控制器,你如果喜欢,也可以将其拆分成多个文件,反正程序在读取时会自动合并。
控制器文件的名称不受限制,但是其内部命名的控制器需要特定几个名称,如下图所示:

当你添加特定名称的动画控制器时,也就意味着先前硬编码的控制器被替换掉了。
提示
如果你发现你的 BlockBench 无法导入动画控制器,请尝试移除 GeckoLib 插件后再重新导入。
目前有这些名称可以用,具体什么意思看英文名应该就懂吧,我就不翻译了:
并行动画
player.pre_parallel_0
player.pre_parallel_1
player.pre_parallel_2
player.pre_parallel_3
player.pre_parallel_4
player.pre_parallel_5
player.pre_parallel_6
player.pre_parallel_7
player.parallel_0
player.parallel_1
player.parallel_2
player.parallel_3
player.parallel_4
player.parallel_5
player.parallel_6
player.parallel_7
主动画
player.main
player.pre_main
player.post_main
手部动画
player.hold_mainhand
player.hold_offhand
player.pre_hold
player.post_hold
player.use
player.pre_use
player.post_use
player.swing
player.pre_swing
player.post_swing
骑乘和盔甲
player.passenger
player.vehicle
player.armor_feet
player.armor_legs
player.armor_chest
player.armor_head
GUI 动画
player.gui_hover
player.gui_focus
模组相关
player.fire(仅用于 tacz 开火)
player.carry_on
player.parcool
maid.misc
maid.statue
箭
注意
2.5.0 版本后,下列控制器被移除,合并入弹射物控制器
详情
arrow.main
arrow.parallel_0
arrow.parallel_1
arrow.parallel_2
arrow.parallel_3
arrow.parallel_4
arrow.parallel_5
arrow.parallel_6
arrow.parallel_7
弹射物
projectile.main
projectile.pre_main
projectile.post_main
projectile.parallel_0
projectile.parallel_1
projectile.parallel_2
projectile.parallel_3
projectile.parallel_4
projectile.parallel_5
projectile.parallel_6
projectile.parallel_7
载具
vehicle.main
vehicle.pre_main
vehicle.post_main
vehicle.ride
vehicle.move
vehicle.pre_parallel_0
vehicle.pre_parallel_1
vehicle.pre_parallel_2
vehicle.pre_parallel_3
vehicle.pre_parallel_4
vehicle.pre_parallel_5
vehicle.pre_parallel_6
vehicle.pre_parallel_7
vehicle.parallel_0
vehicle.parallel_1
vehicle.parallel_2
vehicle.parallel_3
vehicle.parallel_4
vehicle.parallel_5
vehicle.parallel_6
vehicle.parallel_7
第一人称手臂
fp.arm.misc
fp.arm.parallel_0
fp.arm.parallel_1
fp.arm.parallel_2
fp.arm.parallel_3
fp.arm.parallel_4
fp.arm.parallel_5
fp.arm.parallel_6
fp.arm.parallel_7
fp.arm.armor_head
fp.arm.armor_chest
fp.arm.armor_legs
fp.arm.armor_feet
添加的 molang 变量与函数
为了方便控制器,我们包装了部分状态,直接添加了以 ctrl 开头的 molang 变量来方便制作动画控制器。
变量(全是布尔值变量)
| molang | 说明 |
|---|---|
query.all_animations_finished | 当前状态下,控制器的全部动画播放完毕时为 true |
query.any_animation_finished | 当前状态下,控制器的任意动画播放完毕时为 true |
ctrl.death | 死亡时为 true |
ctrl.riptide | 使用三叉戟,触发激流时为 true |
ctrl.sleep | 睡觉时为 true |
ctrl.swim | 游泳时为 true |
ctrl.climb | 趴下并移动时为 true |
ctrl.climbing | 趴下不移动时为 true |
ctrl.ladder_up | 梯子上上爬时为 true |
ctrl.ladder_stillness | 梯子上定住时为 true |
ctrl.ladder_down | 梯子上下滑时为 true |
ctrl.fly | 飞行时为 true |
ctrl.elytra_fly | 鞘翅飞行时为 true |
ctrl.swim_stand | 站立式游泳时为 true |
ctrl.attacked | 被攻击时为 true |
ctrl.jump | 跳跃时为 true |
ctrl.sneak | 潜行移动时为 true |
ctrl.sneaking | 潜行不移动时为 true |
ctrl.run | 跑步时为 true |
ctrl.walk | 行走时时为 true |
ctrl.idle | 待命状态时为 true |
函数
下面几个为 molang 函数,需要填入参数。
其中第二个参数和原来动画命名有点类似,$物品ID,#物品tag,:特殊类别。
| molang | 说明 |
|---|---|
ctrl.hold | 用法:ctrl.hold('mainhand', '$minecraft:apple') |
ctrl.swing | 用法:ctrl.swing('offhand', '#minecraft:axes') |
ctrl.use | 用法:ctrl.use('offhand', ':eat') |
ctrl.armor | 用法:ctrl.armor('head', '$minecraft:iron_helmet')第一个参数有:feet, legs, chest, head |
ctrl.ride | 用法:ctrl.ride('vehicle', '$minecraft:pig')ctrl.ride('passenger', '$minecraft:pig') |
模组兼容相关 molang
| molang | 说明 |
|---|---|
ctrl.carryon_type | 返回字符串 玩家抱起的类型,有三种 block entity player如果没有抱起任何东西,返回空字符串 |
ctrl.carryon_is_princess | 返回布尔值 玩家是否被抱起 |
ctrl.parcool_state | 返回字符串 返回当前正在执行的跑酷动作(内容较多,暂不展示) 如果没有执行任何跑酷动作,返回空字符串 |
ctrl.swem_is_ride | 返回布尔值 玩家是否骑乘 SWEM 的马 |
ctrl.swem_state | 返回字符串 玩家当前正在执行的马术动作 如果没有骑 SWEM 的马,返回空字符串 |
ctrl.tac_hold_gun | 返回布尔值 玩家是否主手持 tacz 的枪械 |
ctrl.tac_gun_type | 返回字符串 玩家当前持有的枪械类型(步枪、手枪那些分类) 如果没有持枪,返回空字符串 |
ctrl.tac_gun_id | 返回字符串 玩家当前持有的枪械 ID 如果没有持枪,返回空字符串 |
ctrl.tac_is_fire | 返回布尔值 玩家是否正在开火 |
ctrl.tac_is_aim | 返回布尔值 玩家是否正在瞄准 |
ctrl.tac_is_reload | 返回布尔值 玩家是否正在重载弹药 |
ctrl.tac_is_melee | 返回布尔值 玩家是否正在近战(刺刀) |
ctrl.tac_is_draw | 返回布尔值 玩家是否正在切枪 |
ctrl.slashblade_animation | 返回字符串 玩家当前打出的剑技名称 如果没有,返回空字符串 |
ctrl.create_hanging_skyhook | 返回布尔值 玩家当前是否在机械动力悬链上悬挂 |
2.6.3 版本动画控制器更新
2.6.3 版本更新了动画控制器的一些机制,以下是控制器的一些变化:
动态动画控制器
以既定的名称创建基岩版控制器,可以为 ysm 的部分插槽添加自定义控制器。同一组内的控制器按名称字母序排序后依次加载,位置越靠后优先级越高。
| 前缀 | 示例 | 插入位置(优先级从低到高) |
|---|---|---|
player.pre_parallel | player.pre_parallel_喵 | 所有控制器的最开头 |
player.pre_main_ | player.pre_main_喵 | player.main(主动画)之前 |
player.post_main_ | player.post_main_喵 | player.main(主动画)之后 |
player.pre_hold_ | player.pre_hold_喵 | player.hold_offhandplayer.hold_mainhand(持有动画)之前 |
player.post_hold_ | player.post_hold_喵喵 | player.hold_offhandplayer.hold_mainhand(持有动画)之后 |
player.pre_swing_ | player.pre_swing_喵 | player.swing(挥动动画)之前 |
player.post_swing_ | player.post_swing_喵喵 | player.swing(挥动动画)之后 |
player.pre_use_ | player.pre_use_喵 | player.use(使用动画)之前 |
player.post_use_ | player.post_use_喵喵 | player.use(使用动画)之后 |
player.parallel | player.parallel_喵 | 控制器末尾 |
硬编码状态
新增名为 ysm-builtin 的内置状态(需手动添加)。当动画控制器进入该状态时调用 ysm 内置的硬编码控制逻辑(即没有基岩版控制器时的逻辑)。
示例
在主动画控制器 player.main 内当 v.idle_type 为 1 时将待机动画替换为飞行动画。

注意
- 该状态过渡时间会影响硬编码控制器;
- 该状态粒子、音效、"进入/退出"表达式正常生效;
- 该状态被视为空状态,其中的动画不会播放;
- molang 脚本控制器在该状态下正常生效。
空状态连续跳转
当动画控制器跳转到一个没有动画的空状态时,会再次检查跳转。
示例
在某一帧内,若动画控制器处于状态 A,同时满足 A -> B -> C 两次跳转,并且 B 是空状态:
- 旧版本行为:仅执行
A -> B跳转,下一帧再重新检查,若仍满足条件才会执行B -> C; - 新版本行为:执行
A -> B -> C连续跳转。
注意
- 若检测到类似于
A -> B -> C -> A -> ...的循环跳转,控制器会停在构成循环前的状态下(即 C); - 连续跳转时,中间状态的粒子、音效、"进入/退出"表达式正常生效。
子控制器
当名为 {父名称} 的控制器跳转到名为 ysm-entry-{子名称} 的状态时,会调用名为 {父名称}.{子名称} 的控制器逻辑。而触发子控制器的状态称为"入口状态"。
示例
在 player.main 控制器下使用 player.main.idle 子控制器,并嵌套了 player.main.idle.type1 子控制器。


注意
- 入口状态的过渡时间无效,但粒子、音效、"进入/退出"表达式正常生效;
- 入口状态被视为空状态,其中的动画不会播放;
- 每帧更新动画时,优先检查父控制器的跳转条件,若从入口状态跳转到其他状态,其对应的子控制器立刻失效并重置;
- 当子控制器失效时,其所处状态的"退出"表达式正常生效;
- 子控制器无法使用
ysm-builtin内置状态; - 子控制器最多嵌套 5 层。
