强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

Godot 4 GDScript 教程 / 动画系统(AnimationPlayer/Tree)

动画系统(AnimationPlayer/Tree)

概述

Godot 4 的动画系统强大且灵活,由 AnimationPlayer(关键帧动画播放器)和 AnimationTree(高级动画混合状态机)两大核心节点组成,支持 2D/3D 属性动画、骨骼动画、动画回调和程序化动画。

节点说明
AnimationPlayer关键帧动画编辑/播放
AnimationTree状态机、混合树、过渡控制
AnimationMixerGodot 4.3+ 动画混合基类

AnimationPlayer 基础

代码播放动画

extends CharacterBody3D

@onready var anim_player: AnimationPlayer = $AnimationPlayer

func play_idle():
    anim_player.play("idle")

func play_run():
    anim_player.play("run", 0.2)  # 0.2 秒过渡

func play_attack():
    anim_player.play("attack")

func _on_animation_finished(anim_name: StringName):
    if anim_name == "attack":
        anim_player.play("idle")

AnimationPlayer 属性轨道

AnimationPlayer 可以动画化几乎任何属性:

轨道类型说明示例
属性轨道Node 属性position, rotation, modulate:a
方法调用轨道调用脚本方法play_footstep_sound()
Bezier 轨道曲线控制复杂缓动
音频轨道播放音效攻击音效
子动画轨道嵌套动画组合动画

方法调用轨道

extends Node3D

@onready var anim_player: AnimationPlayer = $AnimationPlayer

func _ready():
    # 监听动画中的方法调用
    pass

# 在动画编辑器中添加方法调用轨道
# 在特定帧调用此方法
func spawn_attack_effect():
    var effect = preload("res://effects/slash.tscn").instantiate()
    effect.global_position = $WeaponTip.global_position
    get_tree().current_scene.add_child(effect)

func play_slash_sound():
    $SlashSound.play()

AnimationTree 改进

AnimationTree 提供状态机和混合树,是复杂动画系统的核心。

基本设置

extends CharacterBody3D

@onready var anim_tree: AnimationTree = $AnimationTree

func _ready():
    anim_tree.active = true

状态机(StateMachine)

状态机适合管理离散的动画状态(Idle、Run、Jump 等)。

extends CharacterBody3D

@onready var anim_tree: AnimationTree = $AnimationTree

var state_machine: AnimationNodeStateMachinePlayback

func _ready():
    anim_tree.active = true
    state_machine = anim_tree["parameters/playback"]

func _physics_process(delta):
    var h_speed = Vector2(velocity.x, velocity.z).length()

    if not is_on_floor():
        if velocity.y > 0:
            state_machine.travel("Jump")
        else:
            state_machine.travel("Fall")
    elif h_speed > 0.1:
        state_machine.travel("Run")
    else:
        state_machine.travel("Idle")

    # 触发一次性动画
    if Input.is_action_just_pressed("attack"):
        state_machine.travel("Attack")
状态机方法说明
travel("状态名")过渡到目标状态(经过中间状态)
start("状态名")立即切换到目标状态
get_current_node()获取当前状态名
is_playing()是否正在播放

混合树(BlendTree)

混合树适合连续的动画混合(方向混合、上半身/下半身分离等)。

方向混合

extends CharacterBody3D

@onready var anim_tree: AnimationTree = $AnimationTree

func _process(_delta):
    # 更新混合参数
    anim_tree["parameters/BlendSpace/blend_position"] = Vector2(
        velocity.x / 5.0,   # 左右 (-1 ~ 1)
        velocity.z / 5.0    # 前后 (-1 ~ 1)
    )

BlendSpace2D 结构

            Forward (0, -1)
                |
  Left(-1, 0) --+-- Right(1, 0)
                |
            Back (0, 1)

在 AnimationTree 编辑器中设置 BlendSpace2D,在对应位置放置动画片段(Idle、RunForward、RunLeft、RunRight、RunBack 等),引擎自动混合。


动画过渡 AnimationNodeTransition

extends Node3D

@onready var anim_tree: AnimationTree = $AnimationTree

func set_grounded(grounded: bool):
    # 在混合树中使用 Transition 节点切换状态
    anim_tree["parameters/InAir/transition_request"] = "Grounded" if grounded else "Air"

func set_aiming(aiming: bool):
    anim_tree["parameters/AimTransition/transition_request"] = "Aiming" if aiming else "Relaxed"

💡 提示:Godot 4.3+ 中 AnimationNodeTransition 替代了旧的 AnimationNodeOneShot,提供更平滑的过渡。


骨骼动画

骨骼修改器 SkeletonModifier3D

extends Node3D

@onready var skeleton: Skeleton3D = $Armature/Skeleton3D

# IK(反向运动学)让角色看向目标
@onready var ik: LookAtModifier3D = $Armature/Skeleton3D/LookAtModifier3D

var look_target: Vector3 = Vector3.ZERO

func _process(_delta):
    ik.target_position = look_target

物理骨骼

extends Node3D

@onready var phys_bone: PhysicalBoneSimulator3D = $PhysicalBoneSimulator3D

func enable_ragdoll():
    phys_bone.physical_bones_start_simulation()

func disable_ragdoll():
    phys_bone.physical_bones_stop_simulation()

程序化动画

不使用预制动画,通过代码驱动骨骼:

extends Node3D

@onready var skeleton: Skeleton3D = $Armature/Skeleton3D

@export var head_bone: String = "Head"
@export var look_target: Vector3

func _process(_delta):
    var bone_idx = skeleton.find_bone(head_bone)
    if bone_idx == -1:
        return

    # 获取骨骼全局姿态
    var bone_global = skeleton.get_bone_global_pose(bone_idx)

    # 计算朝向
    var dir = (look_target - global_position).normalized()
    var target_rotation = Quaternion(bone_global.basis.looking_at(dir))

    # 平滑旋转
    bone_global.basis = Basis(bone_global.basis.get_rotation_quaternion().slerp(target_rotation, 0.1))

    skeleton.set_bone_global_pose(bone_idx, bone_global)

动画复用与继承

动画资源导入设置

# 在导入时将动画拆分为多个片段
# FBX/glTF 文件可包含多个动画,导入设置中可设置循环等属性

# 代码中复用动画
func setup_animations():
    # 从其他场景复制动画
    var source_anim_player: AnimationPlayer = preload("res://animations/shared_anims.tscn").instantiate().get_node("AnimationPlayer")
    var my_anim_player: AnimationPlayer = $AnimationPlayer

    for anim_name in source_anim_player.get_animation_list():
        var anim = source_anim_player.get_animation(anim_name)
        my_anim_player.add_animation_library("shared", source_anim_player.get_animation_library("shared"))

AnimationLibrary

extends Node3D

@onready var anim_player: AnimationPlayer = $AnimationPlayer

func _ready():
    # 从不同 Library 播放动画
    anim_player.play("shared/idle")     # 共享动画库
    anim_player.play("custom/attack")   # 自定义动画库

2D 帧动画

extends Sprite2D

@onready var anim_player: AnimationPlayer = $AnimationPlayer

# 使用 AnimatedSprite2D 更方便
# 或者用 AnimationPlayer 控制 frame 属性

# AnimatedSprite2D 方式
@onready var animated_sprite: AnimatedSprite2D = $AnimatedSprite2D

func play_walk(direction: String):
    animated_sprite.play("walk_" + direction)  # walk_up, walk_down, walk_left, walk_right

func play_idle():
    animated_sprite.play("idle")

游戏开发场景

场景推荐方案
角色基础动画AnimationTree 状态机
方向移动混合BlendSpace2D
上下半身分离BlendTree + 分层
物理布娃娃PhysicalBoneSimulator3D
UI 动画AnimationPlayer + Control 属性
2D 帧动画AnimatedSprite2D
过场动画AnimationPlayer + 相机轨道

⚠️ 常见陷阱

  1. AnimationTree 必须设 active = true 才能工作
  2. 状态机 travel() 不会立即切换,经过中间状态过渡
  3. 混合树参数类型要匹配,BlendSpace1D 用 float,BlendSpace2D 用 Vector2
  4. 骨骼动画的骨骼名区分大小写
  5. Godot 4.3+ 中 AnimationMixer 统一了 AnimationPlayer 和 AnimationTree 的底层逻辑

扩展阅读