Template:Bedrock Edition Developer Documentation
你可以帮助我们来翻译此条目,但请勿使用机器翻译。
这是基岩版1.12.0的动画文档。
版本:1.12.0.28
概述
当前Minecraft的JSON规范如下:
- 字段应用小写和下划线来表示(无空格)。
- 在定义的目录和子路径下所有的json文件都将会被动画系统所读取使用。
开始
v1.7Beta升级至v1.8
我们根据反馈以及沿着路线来推进技术对代码进行了很小的修改和整理。如果需要升级以前的脚本,您需要对你的所有molang脚本执行以下步骤:
- entity.flags.foo --> query.foo
- entity.member.foo --> query.foo
- entity.foo --> variable.foo
- params.foo --> global.foo
- 一般的规则是
query表示脚本所运行实体的只读值而variable表示用户创建的读写值。 - 我们为所有名称采用了蛇形命名法。如果你愿意的话也可以使用大写字母,因为我们不区分大小写,虽然我们一般建议使用蛇形命名法。
- 之前在生物上设置的一些变量被更改为使用
query.foo的格式。浏览下方的更新列表来查看新内容和更改。
v1.8Beta升级至v1.10
1.10主要的三大改动如下:
- 动画具有在任意深层次结构中可以引用别的动画的能力。
- 动画控制器的参数部分替换成了
variables部分。 - 在实体定义文件中,动画控制器现在列在
animation部分中,并且添加了scripts animate部分以定义要播放的根动画。
v1.8文件格式向后兼容v1.10,因此你不需要_need_来改变任何东西(尽管我们建议按照v1.10的指导重构你的文件,因为新格式会有轻微的性能提升,并使它更容易理解。
添加动画
实体定义
为了让实体具有动画, 你必须将animations和scripts/animate部分添加到实体的实体定义文件中。
你能在这里看见pig.json的的实体定义:
{
"format_version": "1.10.0",
"minecraft:client_entity": {
"description": {
"identifier": "minecraft:pig",
"min_engine_version": "1.8.0",
"materials": { "default": "pig" },
"textures": {
"default": "textures/entity/pig/pig",
"saddled": "textures/entity/pig/pig_saddle"
},
"geometry": {
"default": "geometry.pig.v1.8"
},
"animations": {
"setup": "animation.pig.setup",
"walk": "animation.quadruped.walk",
"look_at_target": "animation.common.look_at_target",
"baby_transform": "animation.pig.baby_transform"
},
"scripts": {
"animate": [
"setup",
{ "walk": "query.modified_move_speed" },
"look_at_target",
{ "baby_transform": "query.is_baby" }
]
},
"render_controllers": [ "controller.render.pig" ],
"spawn_egg": {
"texture": "spawn_egg",
"texture_index": 2
}
}
}
}
注: 因为猪的行走动画与牛、羊的行走动画相同,所以应使用animation.quadruped.walk而不是定义自己的。如果你想自定义一个新的行走动画,你可以修改这一行以指向你自定义的行走动画。
动画被规定为短名称,后可跟其完整的资源名称。该短名称能用于动画控制器和scripts/animate列表,其后的完整名称用于动画文件。
在scripts/animate部分,你需要列出播放的动画以及播放顺序。你能直接指定动画,也能指定混合表达式(blend expression)。
动画控制器
我们需要能够控制动画的播放方式、播放时间以及与其他动画的交互方式。 在实体定义“scripts”中管理大量动画的同时,对动画进行分组动画。控制器示例:
{
"format_version": "1.10.0",
"animation_controllers": {
"controller.animation.my_mob.move": {
"initial_state": "moving",
"states": {
"moving": {
"animations": [
"wag_tail",
"wiggle_ears",
{ "walk": "query.modified_move_speed" }
],
"transitions": [
{ "grazing": "query.is_grazing" }
]
},
"grazing": {
"animations": [ "grazing" ],
"transitions": [
{ "moving": "query.all_animations_finished" }
]
}
}
}
}
}
动画
在每帧开始时,骨架将从其几何定义重置为其默认姿势,然后按顺序为每个通道添加动画。注意通道(x,y,z),动画数据可以是原始数据。
默认情况下,旋转以度为单位,采用先x后y最后z的格式。
"rotation": [90.0, 0.0, 0.0]
也可以是运行时才计算的脚本:
"rotation": ["cos(query.anim_pos * 38.17) * 80.0 * query.anim_speed", 0.0, 0.0]
下面是原版资源包中的animation文件夹中的quadruped.animation.json示例:
{
"format_version": "1.8.0",
"animations": {
"animation.quadruped.walk": {
"anim_time_update": "query.modified_distance_moved",
"loop": true,
"bones": {
"leg0": { "rotation": [ "Math.cos(query.anim_time * 38.17) * 80.0", 0.0, 0.0 ] },
"leg1": { "rotation": [ "Math.cos(query.anim_time * 38.17) * -80.0", 0.0, 0.0 ] },
"leg2": { "rotation": [ "Math.cos(query.anim_time * 38.17) * -80.0", 0.0, 0.0 ] },
"leg3": { "rotation": [ "Math.cos(query.anim_time * 38.17) * 80.0", 0.0, 0.0 ] }
}
}
}
}
动画层次
动画是基于通道的(旋转、位置或缩放),在此范围内,它们是关键帧:
EntityAnimation: animation name __BoneAnimation[]: bone name to animation for this animation ____AnimationChannel[]: rotation, scale, or translation to animate ______KeyFrame[]: the value for the channel to be at, at a specific time
以上所有概念都在下面详细的自下而上的方法中描述。
名称
所有名称(动画、骨骼、状态),都必须以字母开头,并且只包含字母数字、下划线或句点。建议使用全部小写的名称
变换
- 操作顺序:对顶点进行缩放、旋转和平移.
- 假设动画数据是分层的,并按名称应用于骨骼,将动画数据中的骨骼名称与目标几何体的骨架匹配。.
- 不是所有的骨头都需要动画.
- 可以设置目标几何体中不存在的骨骼的动画(忽略丢失的骨骼).
- 对于每个比例、旋转、位置,都可以使用单个值单独或均匀地设置字段。例如,它们是等效的:
"scale": [2.0, 2.0, 2.0] "scale": 2.0 "scale": [2.0]
通道(旋转、位移、缩放)方法
引擎分别跟踪旋转、位置和缩放的动画。在一个通道中,一个或多个关键帧是从动画开始的任意时间(以秒为单位)指定的。
实体动画格式示例
动画的JSON格式如下:
注:与几何格式匹配,单位为1/16米。
"<animation_name>": {
// optional
"loop": <bool> // default = false. Should the animation loop back to t=0.0 when it finishes?
"blend_weight": <expression> // default = "1.0". How much this animation is blended with the others. 0.0 = off. 1.0 = fully apply all transforms. Can be an expression - see the Animation Controller section below
"animation_length": <float> // default = time of last key frame. At what time does the system consider this animation finished?
"override_previous_animation": <bool> // default = false. Should the animation pose of the bone be set to the bind pose before applying this animation, thereby overriding any previous animations to this point?
// required
"bones": [
{
"<bone_name>": { // must match the name of the bone specified in the geometry skeleton
// various flavours of setting data
// omitting a channel skips that channel for this animation of this bone
// any number of floats below can be replaced by a string expression as described above; you don't have to replace all the floats on a line with expressions, only the ones you want to be expression-based
"position": 1.0, // set x, y, and z to 1
"position": [1.0], // set x, y, and z to 1
"position": [1.0, 2.0, 3.0], // set x=1 , y=2 , and z=3
"rotation": 45.0, // set x, y, and z to 45 degrees
"rotation": [45.0], // set x, y, and z to 45 degrees
"rotation": [30.0, 0.0, 45.0], // set x, y, and z to the respective values (in degrees)
// note: only uniform scaling is supported at this time
"scale": 2.0, // scales the bone by 2.0
"scale": [2.0], // scales the bone by 2.0
// Key frame data is described below
// Note that any of the above styles of values will work for "pre" and "post", and "pre" does not have to have the same format as "post"
"rotation": {
"0.0": [80.0, 0.0, 0.0],
"0.1667": [-80.0, 0.0, 0.0],
"0.333": [80.0, 0.0, 0.0]
}
// For discontinuous channel curve, you can specify a different value when interpolating to/from this key frame
"rotation": {
"0.3": { // the key field is the time stamp for this key frame: the value can be any of the above examples
"pre": [30.0, 0.0, 45.0], // when interpolating towards this key frame from the previous, use this value
"post": "180.0 * Math.Sin(global.key_frame_lerp_time)" // when at interpolating away from this key frame to the next, use this value
}
}
// another example
"rotation": {
"0.0": [80.0, 0.0, 0.0], // start at an x rotation of 80 degrees
"0.4": {
"pre": [80.0, 0.0, 0.0], // stay at 80 until 0.4 seconds have elapsed
"post": [0.0, 0.0, 0.0], // discontinuously pop the x rotation to 0.0 degrees
},
"0.8": [-80.0, 0.0, 0.0] // using the previous frame's lerp mode, lerp to a x rotation of -80 degrees by 0.8 seconds
}
}
]
}
关键帧
关键帧为特定通道在指定时间转换为特定骨骼定义两个值,一个值是随着时间接近关键帧时间,另一个值是从该关键帧时间开始的。
插值
目前只支持线性插值。关键帧“pre”和“post”设置允许控制任何关键帧的插值曲线。
- 连续示例:
此示例在1秒内围绕Y轴1旋转骨骼“头部”。
"head": {
"rotation": {
"0.0":[0, 0, 0],
"0.5": [ 0, 180, 0],
"1.0": [0, 360, 0]
}
}
- 单个示例:
不连续仅仅意味着关键帧之间不会有平滑的过渡。如果你想马上发生什么事,这很有用。
此示例缩放骨骼“头”:
1.从0到0.5秒(在“pre”标签中),头骨在所有尺寸上都设置为1的正常比例[x,y,z]
2.在0.5秒时,骨骼将立即扩大到正常大小的2倍,然后
3.从0.5秒到1秒(“post”),骨骼将重新缩放到其所有尺寸的正常比例1。
请注意,在上述文件格式的较大示例中,“pre”和“post”也可以由运行时计算该值的molang表达式定义。允许您有一个数学定义的曲线,而不是纯线性的。
"head": {
"scale": {
"0.5": {
"pre": [1, 1, 1],
"post": 2.0
}
"1.0": [ 1.0 ]
}
}
动画控制器
动画控制器决定播放哪些动画。每个控制器包含播放一个或多个动画的状态列表,每个动画可以在一个或多个参数上混合/控制。
动画控制器格式:
{
"format_version": "1.10.0",
"animation_controllers": {
"controller.animation.sheep.move": {
"states": {
"default": {
"animations": [
{ "walk": "query.modified_move_speed" }
],
"transitions": [
{ "grazing": "query.is_grazing" }
]
},
"grazing": {
"animations": [ "grazing" ],
"transitions": [
{ "default": "query.all_animations_finished" }
]
}
}
}
}
}
状态
状态定义了一组要处理的动画(每个动画都可以有自己的混合值)。每个状态都有一个可选的变量部分,列出引用动画可以使用的任何数量的变量。每个状态也有一个或多个动画,使用实体定义中给定的名称。
- 状态变量
变量可以由游戏设置,也可以由用户定义的脚本设置,该脚本可以在definitions/entity/<entity_name>.json中的实体定义JSON中找到. 变量的值由molang表达式设置。它们还可以通过线性插值曲线重新映射其值。
示例:
这定义了具有单一状态的控制器。
它将创建一个变量variable.ground_speed_curve 它仅在处理该帧的动画控制器时才存在于实体上。
它的价值在于query.ground_speed, 然后在0.2及0.7之间重新映射基于query.ground_speed 从0.0到1.0.它将播放一个动画漫游,当地面速度从停止增加到2.3 m/s时,它将从0.0混合到1.0。
重映射曲线可以有任意数量的条目。
然后动画控制器将播放引用的实体 wiggle_nose 动画,然后是walk 动画, 按以下值缩放后者variable.ground_speed_curve
{
"format_version": "1.10.0",
"animation_controllers": {
"controller.animation.sheep.move": {
"states": {
"default": {
"variables": {
"ground_speed_curve": {
"input": "query.ground_speed",
"remap_curve": {
"0.0": 0.2,
"1.0": 0.7
}
}
},
"animations": [
"wiggle_nose",
{ "walk": "variable.ground_speed_curve" }
]
}
}
}
}
}
- 用户定义的脚本示例
此脚本将把foo设置为query.life的sine-of-query.life的结果,以便稍后在动画或动画控制器中使用。
注意:“pre-animation”告诉脚本在动画发生之前,在一帧中计算出这些变量的值,以便动画可以在自己的公式中使用这些值。如果变量不存在,它将创建一个新变量,其默认值将为0.0。
在definitions\entity\tiger.json中:
{
"custom:tiger":{
"scripts":{
"pre_animation": {
"variable.foo = math.sin(query.life_time)"
}
}
}
}
注意在这个例子中,由于foo等于sin波,所以它的值将在-1到1之间。这意味着您将有一个从0到-1到0的时间段,其中只播放“基础姿势”,然后在相同的时间段内,当foo从0到1回到0时,walk将在基础姿势的顶部播放。基础姿势的混合值为1.0。
"controller.animation.tiger.move": {
"states": {
"default": {
"animations": [
//animations are ADDITIVE unless otherwise specified
//in this case, base_pose will always be playing in the default state
//walk will play as well if Entity.foo is greater than 0.0
"base_pose",
{ "walk": "variable.foo > 0.0" }
]
}
}
}
状态过渡
状态可以指定按顺序列出的任意数量的转换脚本。每个转换都有一个要切换到的目标状态,以及一个脚本来决定是否应该切换。 对于每个顺序的转换,计算脚本,如果它返回非零,则立即切换到指定的状态。
注意:每帧只处理一个转换。
"<controller_name>": {
"states": {
"<state_name>": {
...
"transitions": [
// 按顺序计算以下表达式。
// 第一个返回非零的是要转换到的状态。
//如果都是零,那么不要过渡
{ "<target_state_name_A>", "<expression>" },
{ "<target_state_name_B>", "<expression>" },
...
]
}
},
...
}
示例:
"controller.animation.tiger.move": {
"states": {
"default": {
"animations": [ "base_pose", "walk" ],
"transitions": [
{ "angry": "query.is_angry" }, // 如果query.is_angry返回true,则转换为愤怒状态
{ "tired": "variable.is_tired" } // 如果variable.is_tired返回true,则转换为累态。
]
},
"angry": {
"animations": [ "roar", "extend_claws" ],
"transitions": [
{ "default": "query.any_animation_finished" } // 当咆哮动画或伸展爪动画结束时,切换回默认状态
]
},
"tired": {
"animations": [ "yawn", "stretch" ],
"transitions": [
{ "default": "query.all_animation_finished" } // transition back to default state when the yawn and stretch animations have both finished
]
}
}
}
状态混合
如果您希望在转换时在状态之间有交叉淡入淡出,只需将“混合切换”设置为您希望系统在两个状态之间进行混合的时间。这是作为一个简单的LERP在指定的时间内在两个状态之间完成的。
示例:
"controller.animation.tiger.move": {
"states": {
"default": {
"animations": [ "base_pose", "walk" ],
"transitions": [
{ "angry": "query.is_angry" } // transition to angry state if query.is_angry returns true
],
"blend_transition": 0.2 // when transitioning away from this state, cross-fade over 0.2 seconds
},
"angry": {
"animations": [ "roar", "extend_claws" ],
"transitions": [
{ "default": "query.any_animation_finished" } // transition back to default state when either the roar animation or extend_claws animation finishes
]
}
}
}
渲染控制器
渲染控制器需要一个标识符,并且需要遵循“controller.render.<name>”的格式。此名称需要与客户机实体定义JSON中设置的名称匹配。
渲染控制器是播放机确定实体上渲染内容的一种方法。玩家可以设置实体的几何体、材质、纹理和零件可见性。除了直接设置键,玩家还可以使用数组让实体在不同选项之间进行选择。
开始
要开始在资源包的根目录中创建一个名为“render_controllers”的新文件夹,您需要在其中添加新的render controller json。
豹猫的渲染控制器JSON示例:
"format_version": "1.8.0",
"render_controllers": {
"controller.render.ocelot": {
"arrays": {
"textures": {
"Array.skins": ["Texture.wild", "Texture.black", "Texture.red", "Texture.siamese"]
}
},
"geometry": "Geometry.default",
"materials": [{ "*": "Material.default" }],
"textures": ["Array.skins[query.variant]"]
}
}
示例
羊JSON的几何数组示例
"arrays": {
"geometries": {
"Array.geos": ["Geometry.default", "Geometry.sheared"]
}
},
"geometry": "Array.geos[query.is_sheared]",
蜘蛛JSON的材质示例数组
"arrays": {
"materials": {
"Array.materials": ["Material.default", "Material.invisible"]
}
},
"materials": [{ "*": "Array.materials[query.is_invisible]" }],
村民JSON的纹理示例数组
"arrays": {
"textures": {
"Array.skins": ["Texture.farmer", "Texture.librarian", "Texture.priest", "Texture.smith", "Texture.butcher"]
}
},
"textures": ["Array.skins[query.variant]"]
盔甲渲染控制器JSON中零件着色器的颜色示例:
"format_version": "1.8.0",
"render_controllers": {
"controller.render.armor.chest.v1.0": {
"arrays": {
"materials": {
"array.armor_material": [
"material.armor",
"material.armor_enchanted",
"material.armor_leather",
"material.armor_leather_enchanted"
]
},
"textures": {
"array.armor_texture": [
"texture.leather",
"texture.chain",
"texture.iron",
"texture.diamond",
"texture.gold"
]
}
},
"geometry": "geometry.armor",
"materials" : [
{ "body": "array.armor_material[query.armor_material_slot(1)]" },
{ "leftarm": "array.armor_material[query.armor_material_slot(1)]" },
{ "rightarm": "array.armor_material[query.armor_material_slot(1)]" }
],
"part_visibility" : [
{ "*": 0 },
{ "body": "query.has_armor_slot(1)" },
{ "leftarm": "query.has_armor_slot(1)" },
{ "rightarm": "query.has_armor_slot(1)" }
],
"color": {
"r": "query.armor_color_slot(1, 0)",
"g": "query.armor_color_slot(1, 1)",
"b": "query.armor_color_slot(1, 2)",
"a": "query.armor_color_slot(1, 3)"
},
"textures": ["array.armor_texture[query.armor_texture_slot(1)]", "texture.enchanted"]
}
}
凋零渲染控制器JSON的overlay_color示例:
"format_version": "1.8.0",
"render_controllers": {
"controller.render.wither_boss": {
"arrays": {
"textures": {
"Array.wither_state": ["Texture.invulnerable", "Texture.default"]
}
},
"geometry" : "Geometry.default",
"materials" : [{ "*": "Material.default" }],
"textures" : ["Array.wither_state[variable.display_normal_skin]"],
"overlay_color" : {
"r": "variable.is_invulnerable ? 1.0 : this",
"g": "variable.is_invulnerable ? 1.0 : this",
"b": "variable.is_invulnerable ? 1.0 : this",
"a": "variable.is_invulnerable ? query.overlay_alpha : this"
}
}
}
part_visibility示例,用于从羊驼json打开和关闭零件可见性:
"format_version": "1.8.0",
"render_controllers": {
"controller.render.llama": {
"arrays": {
"textures": {
"Array.base": ["Texture.creamy", "Texture.white", "Texture.brown", "Texture.gray"],
"Array.decor": ["Texture.decor_none", "Texture.decor_white", "Texture.decor_orange", "Texture.decor_magenta", "Texture.decor_light_blue", "Texture.decor_yellow", "Texture.decor_lime", "Texture.decor_pink", "Texture.decor_gray", "Texture.decor_silver", "Texture.decor_cyan", "Texture.decor_purple", "Texture.decor_blue", "Texture.decor_brown", "Texture.decor_green", "Texture.decor_red", "Texture.decor_black"]
}
},
"geometry": "Geometry.default",
"part_visibility": [{ "chest*": "query.is_chested" }],
"materials": [{ "*": "Material.default" }],
"textures": [
"Array.base[query.variant]",
"Array.decor[variable.decor_texture_index]",
"Texture.decor_none"
]
}
}
注意:材质和零件可见性的数组按指定的顺序应用。文件后面指定的材质和零件可见性将覆盖以前的材质或零件。
来自Horse渲染控制器的材质数组示例。马鞍将超越鬃毛,这将超越尾毛等:
"materials": [
{ "*": "Material.default" },
{ "TailA": "Material.horse_hair" },
{ "Mane": "Material.horse_hair" },
{ "*Saddle*": "Material.horse_saddle" }
],