动画状态机文件
动画状态机 (ASM) 文件是动画API的核心. 它们定义了动画的执行方式以及如何使用骨架文件中定义的剪辑。
概念
ASM包含_参数_,剪辑,状态_和_转换(parameters, clips, states 和transitions)。
状态(States )
动画_状态_ 机可以在许多不同的_状态_中。 您可以在状态部分中定义哪些状态。
转换(Transitions)
转换定义允许哪些状态进入其他状态,例如允许“关闭”状态进入“打开”状态。
提示
但是,转换 不会 定义状态之间播放的动画。 如果要这样做,则必须创建一个播放动画的附加状态,然后使用事件转到下一个状态。
参数(Parameters)
提示
参数在代码中称为TimeValues,因此这是SomethingValue的命名约定。
所有参数都采用输入,通常以秒为单位的当前游戏时间作为浮点数(考虑特定tick)并输出另一个时间。 此输出用作剪辑的输入,告诉它当前动画的进展。
每个参数都可以在ASM中定义,也可以在代码中加载ASM时定义。 加载时参数通常是VariableValue类型,它返回一个代码内可变的值,忽略其输入。
其他类型允许你对输入进行数学运算(SimpleExprValue),返回一个常量(ConstValue),引用其他参数(ParameterValue),返回
输入unmodified(IdentityValue)并执行两个参数的组合(CompositionValue)。
剪辑(Clips)
提示
剪辑可以是ASM剪辑,在ASM中定义的剪辑,也可以是电枢剪辑,在骨架文件中定义的剪辑。 对于本页的其余部分,除非另有说明,否则“剪辑”将引用ASM剪辑。
剪辑接收输入,通常是时间,并使用它对模型执行某些操作。 不同类型的剪辑做不同的事情,最简单的是动画电影剪辑(ModelClip)。 您还可以覆盖另一个ASM剪辑的输入(TimeClip)。如果输入为正,则在动画另一个剪辑时触发事件(TriggerClip)。在两个剪辑之间平滑混合(SlerpClip)。 在ASM参考另一个剪辑(ClipReference)或什么也不做(IdentityClip)。
事件(Events)
Various things can trigger events in the ASM. Events in the ASM are represented using only text.
Some events are special, with text that is formatted like this: !event_type:event_value. Right now there is only one kind of event_type, namely transition. This tries to transition to whatever state is defined in the event_value. Anything else is a normal event and can be used from the pastEvents callback, but more information about that is on the implementing page.
各种东西可以触发ASM中的事件。 ASM中的事件仅使用文本表示。
有些事件很特殊,文本格式如下:!event_type:event_value。 现在只有一种event_type,即transition。 这会尝试转换为event_value中定义的任何状态。 其他任何东西都是正常事件,可以从pastEvents回调中使用,但有关它的更多信息在[使用API][implementation]页面上。
编程API
警告
ASM代码API只能用于 客户端 。 在代码中存储ASM时,请使用一端不可知的“IAnimationStateMachine”接口。
可以通过调用ModelLoaderRegistry.loadASM来加载ASM。 它需要两个参数,第一个是ResourceLocation表示
存储ASM的位置,以及第二个加载时定义参数的ImmutableMap。
一个例子:
@Nullable
private final IAnimationStateMachine asm;
private final VariableValue cycle = new VariableValue(4);
public Spin() {
asm = proxy.loadASM(new ResourceLocation(MODID, "asms/block/rotatest.json"), ImmutableMap.of("cycle_length", cycle));
}
在这里,使用一个名为cycle_length的额外参数加载ASM(用端代理SidedProxy以避免在服务器上崩溃)。 这个参数的类型是VariableValue,所以我们可以从我们的代码中设置它。
使用ASM实例,您可以使用.currentState()获取当前状态,并使用.transition(nextState)转换到另一个状态。
VariableValue参数可以通过调用.setValue来设置它们的值,但是你不能读回这个值。 无需通知ASM此更改,它会自动更改。
文件格式
ASM存储在json文件中。 位置无关紧要,但它们通常放在asms文件夹中。
首先是一个例子:
{
"parameters": {
"anim_cycle": ["/", "#cycle_length"]
},
"clips": {
"default": ["apply", "forgedebugmodelanimation:block/rotatest@default", "#anim_cycle" ]
},
"states": [
"default"
],
"transitions": {},
"start_state": "default"
}
如上所述,文件具有参数,剪辑,状态和转换,以及ASM的起始状态。
所有这些标签都是必需的,即使它们是空的。
参数(Parameters)
{
"name": <parameter_definition>
}
<parameter_definition>不同类型的参数有不同的格式,简单的参数是:
IdentityValue:字符串#identity,ParameterValue: 要引用的参数,前缀为#,例如#my_awesome_parameterConstValue: 一个数字用作返回的常量
数学表达式 (SimpleExprValue)
格式: [ regex("[+\\-*/mMrRfF]+"), <parameter_definition>, ... ]
示例:
[ "+", 4 ]
[ "/+", 5, 1]
[ "++", 2, "#other" ]
[ "++", "#other", [ "compose", "#cycle", 3] ]
说明
SimpleExprValue获取其输入并对其应用操作。
第一个参数是要应用的操作序列,其余参数表示这些操作的操作数。每个操作的输入是整个参数的输入(对于第一个操作)或前一个操作的结果。
操作(区分大小写):
| 操作 | 含义 |
|---|---|
+ |
输出 = 输入 + 参数 |
- |
输出 = 输入 - 参数 |
* |
输出 = 输入 * 参数 |
/ |
输出 = 输入 / 参数 |
m |
输出 = min(输入, 参数) |
M |
输出 = max(输入, 参数) |
r |
输出 = floor(输入 / 参数) * 参数 (向下取整) |
R |
输出 = ceil(输入 / 参数) * 参数 (向上取整) |
f |
输出 = 输入 - floor(输入 / 参数) * 参数 (取余) |
F |
输出 = ceil(输入 / 参数) * 参数 - 输入 (参数减余数) |
示例说明:
- 输入 + 4
- (输入 / 5) + 1
- 输入 + 2 +参数
other的值 - 输入 + 参数
other的值+ 参数cycle的值 赋值为 3
功能组件 (CompositionValue)
格式: [ "compose", <parameter_definition>, <parameter_definition> ]
示例:
[ "compose", "#cycle", 3]
[ "compose", "#test", "#other"]
[ "compose", [ "+", 3], "#other"]
[ "compose", [ "compose", "#other2", "#other3"], "#other"]
说明
CompositionValue将两个 参数定义 作为输入,并执行value1(value2(input))。 换句话说,它连接两个输入,用给定的输入调用第二个函数,用第二个输出调用第一个函数。
示例说明:
cycle(3)test(other(输入))3 + other(输入)other2(other3(other(输入)))因为value1=other2(other3(输入)),value2=other(输入)
剪辑(Clips)
{
"name": <clip_definition>
}
与参数一样,不同类型的剪辑
IdentityClip: 字符串#identityClipReference: 要引用的剪辑名,前缀为#,例如#my_amazing_clipModelClip: 模型资源位置+@+骨骼剪辑的名称,例如mymod:block/test@default,mymod:block/test#facing=east@moving
覆盖输入 (TimeClip)
格式: [ "apply", <clip_definition>, <parameter_definition> ]
示例:
["apply", "mymod:block/animated_thing@moving", "#cycle_time"]
["apply", [ "apply", "mymod:block/animated_thing@moving", [ "+", 3 ] ], "#cycle"]
说明
TimeClip采用另一个剪辑并使用自定义参数而不是当前时间来调用它。 通常用于使用参数而不是当前时间来调用ModelClip。
示例说明:
mymod:block/animated_thing@moving(#cycle_time)mymod:block/animated_thing@moving(#cycle + 3)
触发事件 (TriggerClip)
格式: [ "trigger_positive", <clip_definition>, <parameter_definition>, "<event_text>"]
示例
[ "trigger_positive", "#default", "#end_cycle", "!transition:moving" ]
[ "trigger_positive", "mymod:block/animated_thing@moving", "#end_cycle", "boop" ]
说明
TriggerClip在看起来上相当于TimeClip,但当parameter_description变为正时,也会在event_text中触发事件。
同时,它将clip_definition中的剪辑应用于相同的parameter_description。
示例说明
- 在给定参数
end_cycle的输入的情况下应用名为default的剪辑,当end_cycle为正变为到moving状态 - 在给定参数
end_cycle的输入的情况下应用名为mymod:block/animated_thing@moving的剪辑,当end_cycle为正触发boop事件
两个剪辑之间的混合 (SlerpClip)
格式: [ "slerp", <clip_definition>, <clip_definition>, <parameter_definition>, <parameter_definition> ]
示例
[ "slerp", "#closed", "#open", "#identity", "#progress" ]
[ "slerp", [ "apply", "#move", "#mover"], "#end", "#identity", "#progress" ]
说明
SlerpClip在两个独立的剪辑之间执行球形线性混合(spherical linear blend)。 换句话说,它会将一个剪辑平滑地变换为另一个剪辑。
两个clip_definition分别是要混合的剪辑。 第一个parameter_definition是“输入”。 from和to剪辑都以当前动画时间传递此参数的输出。 第二个parameter_definition是“progress”,一个介于0和1之间的值,表示我们在混合中的距离。 将此剪辑与trigger_positive和转换特殊事件组合可以允许两个固态之间的简单转换。
示例说明
- 将“关闭”剪辑混合到“打开”剪辑中,为两个剪辑提供未更改的时间作为输入并混合进度
#progress。 - 当输入参数
mover给定结束剪辑时,将移动剪辑的结果混合,其中未改变的时间作为混合进度#progress的输入。
状态(States)
状态部分只是所有可能状态的列表。
例如
"states": [
"open",
"closed",
"opening",
"closing",
"dancing"
]
定义5 种状态: open, closed, opening, closing 和 dancing.
转换(Transitions)
The transitions section defines which states can go to what other states. A state can go to 0, 1, or many other states.
To define a state as going to no other states, omit it from the section. To define a state as going to only one other state, create a key with the value of the state it can go to, for example "open": "opening". To define a state as going to many other states, do the same as if it were going to only one other state but make the value a list of all possible recieving states instead, for example: "open": ["closed", "opening"].
转换部分定义哪些状态可以转到其他状态。 状态可以进入0,1或许多其他状态。
若要一个状态不能进入其他状态,请从该部分中省略它。 若要一个状态仅能转到另一个状态,请创建一个具有其可以进入的状态值的键,例如"open": "opening"。 要将状态定义为转到许多其他状态,请执行相同的操作,就好像它只转到另一个状态,而是将值作为所有可能的接收状态的列表,例如:"open": ["closed", "opening"]。
一个完整的例子:
"transitions": {
"open": "closing",
"closed": [ "dancing", "opening" ],
"closing": "closed",
"opening": "open",
"dancing": "closed"
}
这个例子是说:
- open状态可以进入closing状态
- closed状态可以进入dancing和opening状态
- closing状态可以进入closed状态
- opening状态可以进入open状态
- dancing状态可以进入closed状态