> 2D 主线有了骨架,本篇给它血肉:AnimationPlayer 的轨道系统、AnimationTree 的状态机与混合空间,外加 4.x 动画系统的重要更新。
一、AnimationPlayer:不只是动 Sprite
新手对 AnimationPlayer 的第一误解是「播放图片序列的工具」。它的本质是属性轨道系统——任何节点的任何属性都能被动画驱动:
- Sprite2D 的 position、modulate;
- 光照的 energy(做灯光闪烁);
- Camera2D 的 offset(做镜头震动);
- 甚至脚本里
@export的自定义变量。
- 值轨道(Value):通用属性,支持关键帧插值与缓动曲线;
- 位置/旋转/缩放 3D 轨道:4.3 重做后支持骨骼重定向(retargeting);
- 方法调用轨道(Method Call):在某一帧调任意函数——脚步声、攻击判定框开关的常规解法;
- Bezier / 音频 / 动画轨道:曲线编辑、配音、以及「动画里套动画」。
animation_finished 信号 + await 是演出脚本的万能胶水:攻击动画结束才解锁输入、开场动画结束才生成敌人,全都是一行 await 的事。二、动画状态机:AnimationTree 的正解
角色状态一多(idle/run/jump/fall/attack/hurt),「在 _physics_process 里手写 if 切动画」就会腐化成面条。正解是 AnimationTree:
- 给角色挂
AnimationTree节点,Tree Root 选 StateMachine; - 把 AnimationPlayer 里的每个动画拖成状态节点,用
play()的 travel 系 API 切换;
@onready var anim_tree: AnimationTree = $%AnimTree
@onready var state_machine := anim_tree.get("parameters/playback") as AnimationNodeStateMachinePlayback
func _physics_process(_delta: float) -> void:
if is_on_floor():
state_machine.travel("run" if absf(velocity.x) > 10.0 else "idle")
else:
state_machine.travel("fall" if velocity.y > 0.0 else "jump")
状态机的三层价值:转移可以带条件与混合时间(0.2 秒的 crossfade 让切换如丝般顺滑);转移有优先与回退语义(hurt 状态可以打断 run,但不能被打断 run);逻辑与表现解耦(动作代码只管 travel,动画细节全在编辑器里调)。
- BlendSpace2D:二维混合空间,最经典用途是 3D 角色的移动动画——横轴速度、纵轴高度,idle/walk/run 四向动画按向量自动混合。
- One-shot 子机:攻击、受击这类「打完回原状态」的一次性动画用它,与主状态机天然隔离。
三、骨架动画与 4.3 重做的红利
Godot 4.3 对 3D 动画做了大改:骨骼重定向让任何 humanoid 骨架模型适配同一套动画库;SkeletonModifier3D 提供程序化骨骼调整的统一挂点。这个方向在 4.6 开花——全新 IK 框架:
- 确定性求解器:
TwoBoneIK3D(双骨,手臂够到目标点)、SplineIK3D(链条/尾巴); - 迭代求解器:
FABRIK3D、CCDIK3D、JacobianIK3D; - 基于
IKModifier3D(SkeletonModifier3D 家族)的模块化设计,可互相组合; - 支持约束(关节扭转与角速度限制),目标可以绑到任意 3D 节点——「手吸附到武器把手」从此是属性配置而非代码。
四、程序化动画:Tween 与代码驱动
不是所有动效都值得建动画资源。临时性、参数化、一次性的动效用 Tween:
var tw := create_tween()
tw.tween_property(sprite, "position:y", -12.0, 0.12).set_trans(Tween.TRANS_QUAD).set_ease(Tween.EASE_OUT)
tw.tween_property(sprite, "position:y", 0.0, 0.18).set_trans(Tween.TRANS_BOUNCE).set_ease(Tween.EASE_OUT)
要点:
create_tween()挂在创建者节点上,节点亡则 Tween 亡,自动清理;.set_trans()/.set_ease()提供三十多种缓动(Quad/Bounce/Elastic/Back……),UI 弹跳手感全靠它们;.set_loops()循环、.set_parallel()并行、.chain()串行、.tween_interval()插入等待;- 4.7 新增
Tween.tween_await():让 Tween 原地暂停直到指定信号发出——对话框与过场演出里「动画等台词」从此一行写完。
_process 里直接改属性。五、性能与工作流小贴士
- 动画越长、轨道越多越吃 CPU(属性插值在主线程),长演出优先考虑 shader/粒子实现;
AnimationPlayer.play()同一动画重复调用不会重置进度(可用play("name", 0.2, 1.0, true)显式控制);- 大量同款动画的资源复用走 Resource(.tres),动画资源可以跨场景共享;
- 2D 精灵图动画也可以走 Sprite2D + AnimationPlayer 的 texture 轨道,但帧动画优先 AnimatedSprite2D,少一层轨道开销。
*本篇配图:状态机圆环流转。*