Godot 节点, AnimationPlayer

介绍 animation tree 节点在 2D 游戏里面的主要应用场景.

animation tree 是和 animation player 一起使用的, 在 animation player 里面定义好了各种动画, 例如往上下左右四个方向移动. 接下来就是在游戏里面, 怎么控制在什么情况下, 播放哪个动画. 也就是需要用代码实现类似以下的逻辑

如果用户上一次的按键是 W
	如果速度是 0, 播放面向上方的静止动画, 否则播放往上移动动画
如果用户上一次的按键是 S
	如果速度是 0, 播放面向下方的静止动画, 否则播放往下移动动画
......

可以看出用代码实现这些逻辑比较繁琐, 如果方向不止 4 个, 而是 8 个. 并且再加上 8 个方向的攻击动画, 代码量会更多.

分解问题

首先从一个比较高的抽象层次看上面的逻辑, 动画可以分成三类, 移动, 静止, 攻击. 每类动画, 又有 8 个方向的变种. 玩家每次只能处于一种状态. 方向由玩家上一次的移动方向确定.

AnimationTree 的 StateMachine 部分负责处理 移动, 静止, 攻击状态的转化. BlendSpace2D 负责处理 8 个方向.

StateMachine

有一个开始节点和一个结束节点, 一开始处在开始节点. 在编辑器里面可以加其他的节点, 最简单的是 Animation 节点 state_machine_add_node

鼠标点击节点前面的播放按钮, 就会把状态机的状态设置到这个节点. node 下面的进度条会开始走动, 并且开始播放动画

注意, 鼠标需要在 “select and move” 的模式下点击才有效 select_and_move

通过代码控制状态机的状态

在编辑器里面可以通过点击节点前面的播放按钮切换状态机的状态. 在代码里面, 需要先拿到 AnimationTree 对象里面的 parameters/playback. 再通过 playback 的 travel 方法, 转换状态

var state_machine = animation_tree.get("parameters/playback")
state_machine.travel("Left")

travel 里面的参数是节点的名字

需要注意现在还没有在编辑器里面添加节点之间的连线, 在没连线的情况下也是可以直接切换状态的, 不需要节点之间一定有连线.

通过连线做自动转换状态

如果直接用代码操作状态机要转换到哪个状态, 那么和之前直接用 AnimationPlayer 对比, 并没有优势

animation_player.play("Left")

状态机的优势在于可以在编辑器里面设置连线让状态自动转化.

点击 AnimationTree tab 上方的 “Connect nodes” 按钮, 把鼠标切换到添加连线的状态 connect 鼠标在想要连线的两个节点之间拖动, 就可以创建连线 connect_action

连线有 Switch Mode 和 Mode 两个属性可以设置

switch mode

把鼠标切换到 “select and move” 模式再点击连线, 在右边可以看到 Switch mode switch_mode

默认是 Immediate 模式, 意思是当切换状态的时候, 如果上一个状态的动画没播放完, 会被马上停止, 直接开始播放下一个动画的开头.

还有另外两个模式是 Sync 模式和 At End 模式. sync 模式表示马上切换到下一个状态的动画, 但是如果上一个动画播放到了第5帧, 那么新状态的动画会在第5帧开始播放.

At End 模式是等待第一个状态的动画播放完了, 才会转化到下一个状态.

mode

Advance 设置里面还有一个 mode mode

默认是 Enabled, Enabled 和 Disabled 是启用和禁用连线. Auto 是当连线起点的节点播放完后, 会自动跳转到连线终点节点.

BlendSpace

之前用的都是简单的节点, 一个节点就对应一个动画. 还有一些类型的节点可以把多个动画组合起来, 这里先讲 BlendSpace1D 和 BlendSpace2D.

Blend 的意思是把多个动画混合在一起, 如果是 3D 的骨骼动画, 可以做到上半身在招手动作, 下半身做跑步动作之类的混合. 1D 2D 指的是动画的混合需要几个维度的输入信息. 例如要做在走路和跑步直接过度, 如果速度低于 x 时播放走路动画, 速度高于 y 时播放跑步动画, x 和 y 之间播放走路和跑步的结合动画. 就可以用 1D. 因为输入维度只有一个, 就是速度. 而如果想要根据玩家的朝向, 播放不同的动画, 就需要 2D 的输入.

创建 BlendSpace1D 类型的节点, 再点击右边的铅笔按钮, 进入节点的编辑页面. blendSpace1d 点击左上角的 Root 可以返回根节点, 也就是刚才状态机的页面. 在 BlendSpace1D 的编辑页面下方, 左下角有 -1, 右下角有 1. 这个是 1D 空间的取值范围. create_points 点击 “Create points” 切换到创建动画点的模式, 在画布中创建 animation add_animation

在这个例子中, 我分别在 -0.5 和 0.5 上创建了两个点. 接下来把鼠标模式切换到 “Set the blending position” 模式 set_blending_position

pointer 如果用鼠标把准星移动到 -0.5 的左边, 那么就会只播放左边的动画 如果把准星移动到 0.5 的右边, 就会只播放右边的动画, 准星在中间的时候, 会播放两个的混合动画.

鼠标模式的右边还有一个 Blend 模式的选项, 可以把默认的实心线段改成 ”- - -”, 即离散模式. 在离散模式里面, 准星距离哪个点最近, 就会直接播放那个点的动画, 没有了中间的混合态.

创建 BlendSpace2D 同理, 变成在 2D 平面上创建点, 准星距离哪个点近, 就会播放哪个点的动画.

在代码中设定 blend 输入值

在编辑器中, 用鼠标移动准星来设置 blend 的输入值, 在代码修改方式是

animation_tree["parameters/BlendSpace1D/blend_position"] = -0.5