Attention: Here be dragons
This is the latest
(unstable) version of this documentation, which may document features
not available in or compatible with released stable versions of Godot.
Checking the stable version of the documentation...
使用 AnimationTree
前言
With AnimationPlayer, Godot has one of the most flexible animation systems that you can find in any game engine. It is pretty much unique in its ability to animate almost any property in any node or resource, and its dedicated transform, bezier, function calling, audio, and sub-animation tracks.
However, the support for blending those animations via AnimationPlayer
is limited, as you can only set a fixed cross-fade transition time.
AnimationTree is a new node introduced in Godot 3.1 to deal with advanced transitions.
It replaces the ancient AnimationTreePlayer
, while adding a huge amount of features and flexibility.
AnimationTree and AnimationPlayer
Before starting, know that an AnimationTree
node does not contain its own animations.
Instead, it uses animations contained in an AnimationPlayer
node. You create, edit, or import your animations in an AnimationPlayer
and then use an AnimationTree
to control the playback.
AnimationPlayer
and AnimationTree
can be used in both 2D and 3D scenes. When importing 3D scenes and their animations, you can use
name suffixes
to simplify the process and import with the correct properties. At the end, the imported Godot scene will contain the animations in an AnimationPlayer
node.
Since you rarely use imported scenes directly in Godot (they are either instantiated or inherited from), you can place the AnimationTree
node in your
new scene which contains the imported one. Afterwards, point the AnimationTree
node to the AnimationPlayer
that was created in the imported scene.
This is how it's done in the Third Person Shooter demo, for reference:

为玩家创建了一个以 CharacterBody3D
为根节点的新场景。这个场景中实例化了原来的 .dae
(Collada)文件,并创建 AnimationTree
节点。
创建树
To use an AnimationTree
, you have to set a root node. An animation root node is a class that contains and evaluates sub-nodes and outputs an animation.
There are 3 types of sub-nodes:
动画节点,从链接的
AnimationTree
中引用动画。Animation Root nodes, which are used to blend sub-nodes and can be nested.
Animation Blend nodes, which are used in an
AnimationNodeBlendTree
, a 2D graph of nodes. Blend nodes take multiple input ports and give one output port.
A few types of root nodes are available:

AnimationNodeAnimation
: Selects an animation from the list and plays it. This is the simplest root node, and generally not used as a root.AnimationNodeBlendTree
: Contains multiple nodes as children in a graph. Many blend nodes are available, such as mix, blend2, blend3, one shot, etc.AnimationNodeBlendSpace1D
: Allows linear blending between two animation nodes. Control the blend position in a 1D blend space to mix between animations.AnimationNodeBlendSpace2D
: Allows linear blending between three animation nodes. Control the blend position in a 2D blend space to mix between animations.AnimationNodeStateMachine
: Contains multiple nodes as children in a graph. Each node is used as a state, with multiple functions used to alternate between states.
混合树
When you make an AnimationNodeBlendTree
, you get an empty 2d graph in the bottom panel, under the AnimationTree tab. It contains only an Output
node by default.

In order for animations to play, a node has to be connected to to the output. You can add nodes from the Add Node.. menu or by right clicking an empty space:

The simplest connection to make is to connect an Animation
node to the output directly, which will just play back the animation.

Following is a description of the other available nodes:
混合2/混合3
这些节点将通过用户指定输入的两个或三个混合值之间进行混合:

Blending can use filters to control individually which tracks get blended and which do not. This can be useful for layering animations on top of each other.

For more complex blending, it is recommended to use blend spaces instead.
OneShot
This node will execute an animation once and return when it finishes. You can customize blend times for fading in and out, as well as filters.

# Play child animation connected to "shot" port.
animation_tree.set("parameters/OneShot/request", AnimationNodeOneShot.ONE_SHOT_REQUEST_FIRE)
# Alternative syntax (same result).
animation_tree["parameters/OneShot/request"] = AnimationNodeOneShot.ONE_SHOT_REQUEST_FIRE
# Abort child animation connected to "shot" port.
animation_tree.set("parameters/OneShot/request", AnimationNodeOneShot.ONE_SHOT_REQUEST_ABORT)
# Alternative syntax (same result).
animation_tree["parameters/OneShot/request"] = AnimationNodeOneShot.ONE_SHOT_REQUEST_ABORT
# Get current state (read-only).
animation_tree.get("parameters/OneShot/active"))
# Alternative syntax (same result).
animation_tree["parameters/OneShot/active"]
// Play child animation connected to "shot" port.
animationTree.Set("parameters/OneShot/request", (int)AnimationNodeOneShot.OneShotRequest.Fire);
// Abort child animation connected to "shot" port.
animationTree.Set("parameters/OneShot/request", (int)AnimationNodeOneShot.OneShotRequest.Abort);
// Get current state (read-only).
animationTree.Get("parameters/OneShot/active");
时间缩放
This node allows you to seek to a time in the animation connected to its in input. Use this node to play an Animation
starting from a certain playback position.
Note that the seek request value is measured in seconds, so if you would like to play an animation from the beginning, set the value to 0.0
, or if you would like
to play an animation from 3 seconds in, set the value to 3.0
.

# Play child animation from the start.
animation_tree.set("parameters/TimeSeek/seek_request", 0.0)
# Alternative syntax (same result).
animation_tree["parameters/TimeSeek/seek_request"] = 0.0
# Play child animation from 12 second timestamp.
animation_tree.set("parameters/TimeSeek/seek_request", 12.0)
# Alternative syntax (same result).
animation_tree["parameters/TimeSeek/seek_request"] = 12.0
// Play child animation from the start.
animationTree.Set("parameters/TimeSeek/seek_request", 0.0);
// Play child animation from 12 second timestamp.
animationTree.Set("parameters/TimeSeek/seek_request", 12.0);
时间缩放
This node allows you to scale the speed of the animation connected to its in input. The speed of the animation will be multiplied by the number in the scale parameter. Setting the scale to 0 will pause the animation. Setting the scale to a negative number will play the animation backwards.

转换
This node is a simplified version of a StateMachine. You connect animations to the inputs, and the current state index determines which animation to play. You may specify a crossfade transition time. In the Inspector, you may change the number of input ports, rearrange inputs, or delete inputs.

# Play child animation connected to "state_2" port.
animation_tree.set("parameters/Transition/transition_request", "state_2")
# Alternative syntax (same result).
animation_tree["parameters/Transition/transition_request"] = "state_2"
# Get current state name (read-only).
animation_tree.get("parameters/Transition/current_state")
# Alternative syntax (same result).
animation_tree["parameters/Transition/current_state"]
# Get current state index (read-only).
animation_tree.get("parameters/Transition/current_index"))
# Alternative syntax (same result).
animation_tree["parameters/Transition/current_index"]
// Play child animation connected to "state_2" port.
animationTree.Set("parameters/Transition/transition_request", "state_2");
// Get current state name (read-only).
animationTree.Get("parameters/Transition/current_state");
// Get current state index (read-only).
animationTree.Get("parameters/Transition/current_index");
状态机
When you make an AnimationNodeStateMachine
, you get an empty 2d graph in the bottom panel, under the AnimationTree tab. It contains a Start
and End
state by default.

To add states, right click or use the create new nodes button, whose icon is a plus in a box. You can add animations, blendspaces, blendtrees, or even another StateMachine. To edit one of these more complex sub-nodes, click on the pencil icon on the right of the state. To return to the original StateMachine, click Root on the top left of the panel.
Before the StateMachine can do anything useful, the states must be connected with transitions. To add a transition, click the connect nodes button, which is a line with a right-facing arrow, and drag between two states. You can create 2 transitions between states, one going in each direction.

There are 3 types of transitions:

Immediate: Will switch to the next state immediately.
Sync(同步):立即切换到下一个状态,但会将新状态快进并到旧状态的播放位置。
At End(末尾):将等待当前状态播放结束,然后切换到下一个状态动画的开头。
Transitions also have a few properties. Click a transition and it will be displayed in the inspector:

Xfade Time(叠化时间)是在这个状态和下一个状态之间交叉渐变的时间。
Xfade Curve is a cross-fade following a curve rather than a linear blend.
Reset determines whether the state you are switching into plays from the beginning (true) or not (false).
Priority(优先级)与代码中的
travel()
函数一起使用(后述)。当从一个状态到另一个状态时,会优先使用优先级较低的过渡。Switch Mode is the transition type (see above). It can be changed after creation here.
Advance Mode determines the advance mode. If
Disabled
, the transition will not be used. IfEnabled
, the transition will only be used duringtravel()
. IfAuto
, the transition will be used if the advance condition and expression are true, or if there are no advance conditions/expressions.
Advance Condition and Advance Expression
The last 2 properties in a StateMachine transition are Advance Condition
and Advance Expression.
When the Advance Mode is set to Auto, these
determine if the transition will advance or not.
Advance Condition is a true/false check. You may put a custom variable name in the text field, and when the StateMachine reaches this transition, it will check if your variable is true. If so, the transition continues. Note that the advance condition only checks if a variable is true, and it cannot check for falseness.
This gives the Advance Condition a very limited capability. If you wanted to make a transition back and forth based on one property, you would need to make 2 variables that have opposite values, and check if either of them are true. This is why, in Godot 4, the Advance Expression was added.
The Advance Expression works similar to the Advance Condition, but instead of checking if one variable is true, it evaluates any expression. An expression
is anything you could put in an if
statement. These are all examples of expressions that would work in the Advance Expression:
is_walking
is_walking
== trueis_walking && !is_idle
velocity > 0
player.is_on_floor()
Here is an example of an improperly-set-up StateMachine transition using Advance Condition:


This is not working because there is a !
variable in the Advance Condition, which cannot be checked.
Here is the same example, set up properly, using two opposite variables:


Here is the same example, but using Advance Expression rather than Advance Condition, which eliminates the need for two variables:



In order to use Advance Expressions, the Advance Expression Base Node has to be set from the Inspector of the AnimationTree node. By default, it is set to the AnimationTree node itself, but it needs to point to whatever node contains the script with your animation variables.
StateMachine travel
One of the nice features in Godot's StateMachine
implementation is the ability to travel. You can instruct the graph to go from the
current state to another one, while visiting all the intermediate ones. This is done via the A* algorithm.
If there is no path of transitions starting at the current state and finishing at the destination state, the graph teleports to the destination state.
To use the travel ability, you should first retrieve the AnimationNodeStateMachinePlayback
object from the AnimationTree
node (it is exported as a property), and then call one of its many functions:
var state_machine = animation_tree["parameters/playback"]
state_machine.travel("SomeState")
AnimationNodeStateMachinePlayback stateMachine = (AnimationNodeStateMachinePlayback)animationTree.Get("parameters/playback");
stateMachine.Travel("SomeState");
The StateMachine must be running before you can travel. Make sure to either call start()
or connect a node to Start.
BlendSpace2D and BlendSpace1D
BlendSpace2D
is a node to do advanced blending in two dimensions. Points representing animations are added to a 2D space and then a position between them
is controlled to determine the blending:

You may place these points anywhere on the graph by right clicking or using the add point button, whose icon is a pen and point. Wherever you place the points, the triangle between them will be generated automatically using Delaunay. You may also control and label the ranges in X and Y.

Finally, you may also change the blend mode. By default, blending happens by interpolating points inside the closest triangle. When dealing with 2D animations (frame by frame), you may want to switch to Discrete mode. Alternatively, if you want to keep the current play position when switching between discrete animations, there is a Carry mode. This mode can be changed in the Blend menu:

BlendSpace1D works just like BlendSpace2D, but in one dimension (a line). Triangles are not used.

为了更好的混合
在 Godot 4.0+ 中,为了使混合结果具有确定性(结果可复现且始终一致),混合属性值必须具有特定的初始值。例如,在要混合两个动画的情况下,如果一个动画具有属性轨道而另一个动画没有,则计算混合动画时,要好像后一个动画(即本来没有属性轨道的那个)具有初始值的属性轨道一样去处理。
当使用 Skeleton3D 骨骼的 Position/Rotation/Scale 3D 轨道时,初始值为 Bone Rest(骨骼放松姿势)。对于其他属性而言,初始值是 0
,并且如果轨道出现在 RESET
动画中,那么则使用它第一个关键帧的值。
例如,下面的 AnimationPlayer 有两个动画,但其中一个缺少 Position 的属性轨道。

这意味着缺少该 Position 的动画会将这些 Position 视为 Vector2(0, 0)
。

可以通过将 Position 的 Property 轨道作为初始值添加到 RESET
动画中来解决这个问题。


备注
请注意,RESET
动画的存在是为了在最初加载对象时定义默认姿势。它被假定只有一帧,并且不应使用时间轴进行播放。
Also keep in mind that the Rotation 3D tracks and the Property tracks for 2D rotation with Interpolation Type set to Linear Angle or Cubic Angle will prevent rotations greater than 180 degrees from the initial value as blended animation.
这种限制对于 Skeleton3D 非常有用,可以防止骨骼在混合动画时穿透身体。因此,Skeleton3D 的 Bone Rest (骨骼放松姿势)值应尽可能接近可移动范围的中点。 这意味着人形模型最好以 T-pose 导入 。

你可以看到,优先考虑从 Bone Rest 出发的最短旋转路径,而不是动画之间的最短旋转路径。
如果需要通过混合动画将 Skeleton3D 本身旋转 180 度以上,则可以使用 Root Motion。
根骨骼运动
处理 3D 动画时,一种流行的技术是动画师利用根骨骼为其余部分骨骼制作运动动画。这样处于动画角色的脚步就能够与下方的地板相匹配,并且还能够实现过场动画中与物体的精确交互。
在 Godot 中回放动画时,可以将这根骨骼选作根运动轨道。这会在视觉上取消这根骨骼的变换(在原地播放动画)。

这样做以后,可以通过 AnimationTree API 获取实际的变换:
# Get the motion delta.
animation_tree.get_root_motion_position()
animation_tree.get_root_motion_rotation()
animation_tree.get_root_motion_scale()
# Get the actual blended value of the animation.
animation_tree.get_root_motion_position_accumulator()
animation_tree.get_root_motion_rotation_accumulator()
animation_tree.get_root_motion_scale_accumulator()
// Get the motion delta.
animationTree.GetRootMotionPosition();
animationTree.GetRootMotionRotation();
animationTree.GetRootMotionScale();
// Get the actual blended value of the animation.
animationTree.GetRootMotionPositionAccumulator();
animationTree.GetRootMotionRotationAccumulator();
animationTree.GetRootMotionScaleAccumulator();
可以将这些值提供给 CharacterBody3D.move_and_slide 等函数,用来控制角色的移动。
There is also a tool node, RootMotionView
, you can place a scene that will act as a custom floor for your
character and animations (this node is disabled by default during the game).

使用代码控制
创建树和预览之后,就只剩下一个问题:“这些东西怎么使用代码来控制?”。
Keep in mind that the animation nodes are just resources, so 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 StateMachine or blend space) in different animation trees.
实际的动画数据包含在 AnimationTree
节点中, 并通过属性访问. 检查 AnimationTree
节点的 "参数" 部分, 查看所有可以实时修改的参数:

This is handy because it makes it possible to animate them from an AnimationPlayer
, or even the AnimationTree
itself,
allowing very complex animation logic.
To modify these values from code, you must obtain the property path. You can find them by hovering your mouse over any of the parameters:

Then you can set or read them:
animation_tree.set("parameters/eye_blend/blend_amount", 1.0)
# Alternate syntax (same result)
animation_tree["parameters/eye_blend/blend_amount"] = 1.0
animationTree.Set("parameters/eye_blend/blend_amount", 1.0);
备注
Advance Expressions from a StateMachine will not be found under the parameters. This is because they are held in another script rather than the AnimationTree itself. Advance Conditions will be found under parameters.