使用 AnimationTree

前言

With AnimationPlayer, Godot has one of the most flexible animation systems that you can find in any game engine. The ability to animate almost any property in any node or resource, as well as having dedicated transform, bezier, function calling, audio and sub-animation tracks, is pretty much unique.

然而, 通过 AnimationPlayer 混合这些动画的支持相对有限, 只能设置固定的交叉渐变过渡时间.

AnimationTree 是Godot 3.1中引入的一个新节点, 用于处理更高级的变换, 它取代了旧的 AnimationTreePlayer , 同时增加了大量的功能和灵活性.

创建动画树

首先, 必须明确 AnimationTree 节点不包含它自己的动画. 相反, 它使用包含在 AnimationPlayer 节点中的动画. 通过这种形式, 您可以像往常一样编辑动画(或从3D场景导入动画), 然后使用这个额外节点来控制播放.

在3D场景中经常使用 AnimationTree . 当从3D交换格式导入场景时, 它们通常自带动画(要么是多个, 要么是在导入时从一个大的动画中拆分出来). 最后, 导入的Godot场景在 AnimationPlayer 节点中包含动画.

很少在Godot中直接使用导入的场景(它们要么实例化, 要么来自继承), 您可以将 AnimationTree 节点放置在包含导入的新场景中. 然后, 将 AnimationTree 节点指向导入场景内创建的 AnimationPlayer 节点.

这是在 第三人称射击游戏演示, 中的设置, 参考下图:

../../_images/animtree1.png

为玩家创建了一个以 KinematicBody 为根节点的新场景. 在这个场景中, 已实例化原来的 .dae (Collada)文件, 并创建 AnimationTree 节点.

创建树

可以在 AnimationTree 中使用三种主要节点类型:

  1. 动画节点, 从链接的 AnimationTree 中引用动画.

  2. 动画根节点, 用于混合子节点.

  3. 动画混合节点,在 AnimationNodeBlendTree 中使用,通过多个输入端口进行单图混合。

AnimationTree 中设置根节点, 如下几种类型可供选择:

../../_images/animtree2.png

  • AnimationNodeAnimation:从列表中选择一个动画并播放它. 这是最简单的根节点, 一般不直接用作根节点.

  • AnimationNodeBlendTree:包含许多混合类型的节点,如调配, 混合2, 混合3, 一对一等. 这是最常用的根节点之一.

  • AnimationNodeStateMachine:将多个根节点作为图中的子节点. 每个节点作为一个 状态 使用, 并提供多个函数在状态之间进行切换.

  • AnimationNodeBlendSpace2D:允许在二维混合空间中放置根节点. 在二维中控制混合位置以混合多个动画.

  • AnimationNodeBlendSpace1D:以上的简化版本(一维)。

混合树

AnimationNodeBlendTree 可包含用于混合的根节点和常规节点。节点从菜单添加到图中:

../../_images/animtree3.png

所有混合树默认都包含一个 Output(输出)节点,为了让动画播放,必须有个东西与其相连。

测试此功能最简单的方法是直接连接一个 Animation(动画)节点:

../../_images/animtree4.png

这会简单地回放动画. 确保 AnimationTree 节点对实际发生的事情是激活的.

以下是可用节点的简短描述:

混合2/混合3

这些节点将通过用户指定输入的两个或三个混合值之间进行混合:

../../_images/animtree5.gif

对于更复杂的混合, 建议使用混合空间.

混合也可以使用过滤器, 也就是说, 您可以单独控制通过混合功能的轨道. 这对于动画的层叠非常有用.

../../_images/animtree6.png

OneShot

此节点将执行子动画, 并在完成后返回. 可以用于定制淡入淡出时间, 以及过滤器.

../../_images/animtree6b.gif

查找

这个节点可以用来使寻找命令发生在动画图像的任何子代上。使用这个节点类型可以从 AnimationNodeBlendTree 中的开始或某个位置播放 Animation

在设置时间和改变动画播放后,寻找节点通过设置其 seek_position 值为 -1.0,在下一个进程帧自动进入睡眠模式。

GDScriptC#

  1. # Play child animation from the start.
  2. anim_tree.set("parameters/Seek/seek_position", 0.0)
  3. # Alternative syntax (same result as above).
  4. anim_tree["parameters/Seek/seek_position"] = 0.0
  5. # Play child animation from 12 second timestamp.
  6. anim_tree.set("parameters/Seek/seek_position", 12.0)
  7. # Alternative syntax (same result as above).
  8. anim_tree["parameters/Seek/seek_position"] = 12.0
  1. // Play child animation from the start.
  2. animTree.Set("parameters/Seek/seek_position", 0.0);
  3. // Play child animation from 12 second timestamp.
  4. animTree.Set("parameters/Seek/seek_position", 12.0);

时间缩放

允许缩放任何子节点的动画速度(或将其反转). 设置为0会暂停动画.

转换

非常简单的状态机(当您不想使用 StateMachine 节点时)。动画可以连接到输出,并且可以指定过渡时间。

二维混合空间

BlendSpace2D 是一个在二维空间进行高级混合的节点. 将点添加到一个二维空间, 然后可以控制位置来确定混合:

../../_images/animtree7.gif

可以控制X和Y的范围(为方便起见, 还可以标记它们). 默认情况下, 可以在任何位置放置点(只需右键单击坐标系统或使用 添加点 按钮)将自动生成德洛内三角形.

../../_images/animtree8.gif

也可以通过禁用 自动三角形 选项来手动绘制三角形, 虽然基本上没必要这么做:

../../_images/animtree9.png

最后, 可能会更改混合模式. 默认情况下, 混合是通过在最近的三角形内插点来实现的. 当处理二维动画(逐帧)时, 您可能希望切换到 离散 模式. 此外, 如果您想在离散动画之间切换时保持当前播放位置, 请使用 进位 模式. 此模式可在 混合 菜单中更改:

../../_images/animtree10.png

一维混合空间

这类似于二维混合空间, 但在一维空间中(所以不需要三角形).

状态机

This node acts as a state machine with root nodes as states. Root nodes can be created and connected via lines. States are connected via Transitions, which are connections with special properties. Transitions are uni-directional, but two can be used to connect in both directions.

../../_images/animtree11.gif

There are many types of transition:

../../_images/animtree12.png

  • Immediate: 将立即切换到下一个状态. 当前状态将结束, 并融合到新状态的开始.

  • 同步: 立即切换到下一个状态, 但会将新状态搜索并放置到旧状态的回放位置.

  • 末尾: 将等待当前状态回放结束, 然后切换到下一个状态的开始动画.

过渡也有一些属性。单击任何过渡,它就会显示在“检查器”面板中:

../../_images/animtree13.png

  • 切换模式 为过渡类型(见上文), 可以在此处创建后修改.

  • 自动前进 当达到此状态时将自动开启转换. 最适合 “末尾” 切换模式.

  • 前进条件 设置此条件后, 将打开自动前进. 这是一个可以用变量名填充的自定义文本字段. 可以从代码中修改变量(稍后将对此进行详细介绍).

  • X消隐时间 是在这个状态和下一个状态之间交替渐变的时间.

  • Priority is used together with the travel() function from code (more on this later). Lower priority transitions are preferred when travelling through the tree.

  • Disabled toggles disabling this transition (when disabled, it will not be used during travel or auto advance).

根骨骼运动

处理 3D 动画时,一种流行的技术是动画师利用根骨骼为其余部分骨骼制作运动动画。这使得动画角色的脚步与下面的地板相匹配。并且允许在电影拍摄期间与物体进行精确的交互。

在 Godot 中回放动画时,可以选择这根骨骼作为根运动轨迹。这会在视觉上取消这根骨骼的变换(动画将保持原状)。

../../_images/animtree14.png

然后, 实际运动可以通过 AnimationTree API 作为转换:

GDScriptC#

  1. anim_tree.get_root_motion_transform()
  1. animTree.GetRootMotionTransform();

可以提供给 KinematicBody.move_and_slide 等函数,用来控制角色移动。

There is also a tool node, RootMotionView, that can be placed in a scene and will act as a custom floor for your character and animations (this node is disabled by default during the game).

../../_images/animtree15.gif

使用代码控制

创建树和预览之后, 只剩下一个问题:”如何使用代码控制所有的节点?”.

Keep in mind that the animation nodes are just resources and, as such, they are shared between all instances using them. Setting values in the nodes directly will affect all instances of the scene that uses this AnimationTree. This is generally undesirable, but does have some cool use cases, e.g. you can copy and paste parts of your animation tree, or reuse nodes with a complex layout (such as a state machine or blend space) in different animation trees.

实际的动画数据包含在 AnimationTree 节点中, 并通过属性访问. 检查 AnimationTree 节点的 “参数” 部分, 查看所有可以实时修改的参数:

../../_images/animtree16.png

这很方便, 因为它可以通过 AnimationPlayer 获得动画效果, 甚至是 AnimationTree 本身, 允许实现非常复杂的动画逻辑.

想要通过代码修改这些值, 必须获得该属性的路径. 这是很容易做到的, 把鼠标悬停在任何参数:

../../_images/animtree17.png

允许设置或读取它们:

GDScriptC#

  1. anim_tree.set("parameters/eye_blend/blend_amount", 1.0)
  2. # Simpler alternative form:
  3. anim_tree["parameters/eye_blend/blend_amount"] = 1.0
  1. animTree.Set("parameters/eye_blend/blend_amount", 1.0);

状态机行程

One of the nice features in Godot’s StateMachine implementation is the ability to travel. The graph can be instructed to go from the current state to another one, while visiting all the intermediate ones. This is done via the A* algorithm. In the absence of any viable set of transitions starting at the current state and finishing at the destination state, the graph teleports to the destination state.

要使用行程能力, 您应该首先从 AnimationTree 节点中检索 AnimationNodeStateMachinePlayback 对象(其被导出为一个属性).

GDScriptC#

  1. var state_machine = anim_tree["parameters/playback"]
  1. AnimationNodeStateMachinePlayback stateMachine = (AnimationNodeStateMachinePlayback)animTree.Get("parameters/playback");

一旦检索到, 可以调用它提供的许多函数之一:

GDScriptC#

  1. state_machine.travel("SomeState")
  1. stateMachine.Travel("SomeState");

状态机必须正在运行才能使用行程能力。确保调用 start() 或选择一个节点以在加载时自动播放

../../_images/animtree18.png