使用 AnimationTree
前言
通过 AnimationPlayer,Godot 拥有你在所有游戏引擎中能找到的最灵活的动画系统之一。可以在任何节点或资源中对任何属性进行动画处理,以及专门的变换、贝塞尔、函数调用、音频和子动画轨道,这样的能力相当独特。
然而, 通过 AnimationPlayer
混合这些动画的支持相对有限, 只能设置固定的交叉渐变过渡时间.
AnimationTree 是Godot 3.1中引入的一个新节点, 用于处理更高级的变换, 它取代了旧的 AnimationTreePlayer
, 同时增加了大量的功能和灵活性.
创建动画树
首先, 必须明确 AnimationTree
节点不包含它自己的动画. 相反, 它使用包含在 AnimationPlayer
节点中的动画. 通过这种形式, 您可以像往常一样编辑动画(或从3D场景导入动画), 然后使用这个额外节点来控制播放.
在3D场景中经常使用 AnimationTree
. 当从3D交换格式导入场景时, 它们通常自带动画(要么是多个, 要么是在导入时从一个大的动画中拆分出来). 最后, 导入的Godot场景在 AnimationPlayer
节点中包含动画.
很少在Godot中直接使用导入的场景(它们要么实例化, 要么来自继承), 您可以将 AnimationTree
节点放置在包含导入的新场景中. 然后, 将 AnimationTree
节点指向导入场景内创建的 AnimationPlayer
节点.
这是在 第三人称射击游戏演示, 中的设置, 参考下图:
为玩家创建了一个以 KinematicBody
为根节点的新场景. 在这个场景中, 已实例化原来的 .dae
(Collada)文件, 并创建 AnimationTree
节点.
创建树
可以在 AnimationTree
中使用三种主要节点类型:
动画节点, 从链接的
AnimationTree
中引用动画.动画根节点, 用于混合子节点.
动画混合节点, 它们在 “动画节点混合树” 中使用, 通过多个输入端口作为单图混合.
在 AnimationTree
中设置根节点, 如下几种类型可供选择:
“动画节点动画”: 从列表中选择一个动画并播放它. 这是最简单的根节点, 一般不直接用作根节点.
“动画节点混合树”: 包含许多 混合 类型的节点, 如调配, 混合2, 混合3, 一对一等. 这是最常用的根节点之一.
“动画节点状态机”: 将多个根节点作为图中的子节点. 每个节点作为一个 状态 使用, 并提供多个函数在状态之间进行切换.
“动画节点二维混合空间”: 允许在二维混合空间中放置根节点. 在二维中控制混合位置以混合多个动画.
“动画节点一维混合空间”: 以上的简化版本(一维).
混合树
一个 “动画节点混合树” 可包含用于混合的根节点和常规节点. 节点从菜单添加到图中:
所有混合树默认包含一个 “输出” 节点, 为了让动画播放, 必须有个东西与其相连.
测试此功能最简单的方法是直接连接一个 “动画” 节点:
这会简单地回放动画. 确保 AnimationTree
节点对实际发生的事情是激活的.
以下是可用节点的简短描述:
混合2/混合3
这些节点将通过用户指定输入的两个或三个混合值之间进行混合:
对于更复杂的混合, 建议使用混合空间.
混合也可以使用过滤器, 也就是说, 您可以单独控制通过混合功能的轨道. 这对于动画的层叠非常有用.
OneShot
此节点将执行子动画, 并在完成后返回. 可以用于定制淡入淡出时间, 以及过滤器.
查找
这个节点可以用来使寻找命令发生在动画图像的任何子代上。使用这个节点类型可以从 AnimationNodeBlendTree
中的开始或某个位置播放 Animation
。
在设置时间和改变动画播放后,寻找节点通过设置其 seek_position 值为 -1.0 ,在下一个进程帧自动进入睡眠模式。
GDScript
C#
# Play child animation from the start.
anim_tree.set("parameters/Seek/seek_position", 0.0)
# Alternative syntax (same result as above).
anim_tree["parameters/Seek/seek_position"] = 0.0
# Play child animation from 12 second timestamp.
anim_tree.set("parameters/Seek/seek_position", 12.0)
# Alternative syntax (same result as above).
anim_tree["parameters/Seek/seek_position"] = 12.0
// Play child animation from the start.
animTree.Set("parameters/Seek/seek_position", 0.0);
// Play child animation from 12 second timestamp.
animTree.Set("parameters/Seek/seek_position", 12.0);
时间缩放
允许缩放任何子节点的动画速度(或将其反转). 设置为0会暂停动画.
转换
非常简单的状态机(当您不想使用 “状态机” 节点时). 动画可以连接到输出, 并且可以指定转换时间.
二维混合空间
BlendSpace2D
是一个在二维空间进行高级混合的节点. 将点添加到一个二维空间, 然后可以控制位置来确定混合:
可以控制X和Y的范围(为方便起见, 还可以标记它们). 默认情况下, 可以在任何位置放置点(只需右键单击坐标系统或使用 添加点 按钮)将自动生成德洛内三角形.
也可以通过禁用 自动三角形 选项来手动绘制三角形, 虽然基本上没必要这么做:
最后, 可能会更改混合模式. 默认情况下, 混合是通过在最近的三角形内插点来实现的. 当处理二维动画(逐帧)时, 您可能希望切换到 离散 模式. 此外, 如果您想在离散动画之间切换时保持当前播放位置, 请使用 进位 模式. 此模式可在 混合 菜单中更改:
一维混合空间
这类似于二维混合空间, 但在一维空间中(所以不需要三角形).
状态机
这个节点是个相对简单的状态机. 根节点可以创建并通过线路连接. 状态通过 转换 连接, 它们是具有特殊性质的连接. 转换是单向的, 但是可以用两种方式连接.
有多种类型的转换:
Immediate: 将立即切换到下一个状态. 当前状态将结束, 并融合到新状态的开始.
同步: 立即切换到下一个状态, 但会将新状态搜索并放置到旧状态的回放位置.
末尾: 将等待当前状态回放结束, 然后切换到下一个状态的开始动画.
转换也有一些属性. 点击任何转换, 它会显示在属性面板中:
切换模式 为过渡类型(见上文), 可以在此处创建后修改.
自动前进 当达到此状态时将自动开启转换. 最适合 “末尾” 切换模式.
前进条件 设置此条件后, 将打开自动前进. 这是一个可以用变量名填充的自定义文本字段. 可以从代码中修改变量(稍后将对此进行详细介绍).
X消隐时间 是在这个状态和下一个状态之间交替渐变的时间.
优先级 与代码中的
travel()
函数一起使用(稍后再谈). 当从一个状态到另一个状态时, 当给这个节点更多的优先权.禁用 允许禁用此转换(它不会在行程或自动前进期间使用).
根骨骼运动
当处理3D动画时, 一种流行的技术是动画师利用根骨骼为其余部分骨骼制作运动动画. 这使得动画角色的脚步与下面的地板相匹配. 并且允许在电影拍摄期间与物体进行精确的交互.
在Godot中回放动画时, 可以选择这根单根骨作为 根运动轨迹. 这会在视觉上取消单根骨的转换(动画将保持原状).
然后, 实际运动可以通过 AnimationTree API 作为转换:
GDScript
C#
anim_tree.get_root_motion_transform()
animTree.GetRootMotionTransform();
可以提供给 KinematicBody.move_and_slide 等函数,用来控制角色移动。
还有一个名为 “根骨骼运动视图” 的工具节点, 可以放置在场景中, 并作为你的角色和动画的自定义地板(此节点通常在游戏期间禁用).
使用代码控制
创建树和预览之后, 只剩下一个问题:”如何使用代码控制所有的节点?”.
要注意动画节点就是资源, 并且因此他们在所有实例之间共享. 直接修改节点中的值, 将会影响到场景中所有使用这个 AnimationTree
的实例. 不过这也有一些不错的用法, 比如你可以复制粘贴你的动画树的一部分, 或者在不同的动画树中复用具有复杂布局的节点(例如状态机和混合树).
实际的动画数据包含在 AnimationTree
节点中, 并通过属性访问. 检查 AnimationTree
节点的 “参数” 部分, 查看所有可以实时修改的参数:
这很方便, 因为它可以通过 AnimationPlayer
获得动画效果, 甚至是 AnimationTree
本身, 允许实现非常复杂的动画逻辑.
想要通过代码修改这些值, 必须获得该属性的路径. 这是很容易做到的, 把鼠标悬停在任何参数:
允许设置或读取它们:
GDScript
C#
anim_tree.set("parameters/eye_blend/blend_amount", 1.0)
# Simpler alternative form:
anim_tree["parameters/eye_blend/blend_amount"] = 1.0
animTree.Set("parameters/eye_blend/blend_amount", 1.0);
状态机行程
执行 “状态机” 的行程能力, 是Godot引擎的优秀特性之一. 可以指示图表从当前状态转到另一个状态, 我们可以访问其所有的中间状态. 这是通过A*算法实现的.
要使用行程能力, 您应该首先从 AnimationTree
节点中检索 AnimationNodeStateMachinePlayback 对象(其被导出为一个属性).
GDScript
C#
var state_machine = anim_tree["parameters/playback"]
AnimationNodeStateMachinePlayback stateMachine = (AnimationNodeStateMachinePlayback)animTree.Get("parameters/playback");
一旦检索到, 可以调用它提供的许多函数之一:
GDScript
C#
state_machine.travel("SomeState")
stateMachine.Travel("SomeState");
状态机必须正在运行才能使用行程能力. 确保调用 start()
或选择一个节点以 在加载时自动播放 .