mcpField
A
animation-system

animation-system

github.com/jame581开发889185 次安装4 天前更新
代码仓库

关于 animation-system

面向 Godot 4.3+ 开发者的动画系统技能,介绍 AnimationPlayer、AnimationTree、精灵动画及 3D 骨骼动画,示例使用 GDScript 和 C#。

主要功能

  1. 01AnimationPlayer 播放与控制
  2. 02AnimationTree 状态机和混合
  3. 03精灵帧动画
  4. 04动画信号与方法调用轨道
  5. 053D 骨骼修饰器与 IK
  6. 06动画标记和重定向

适用场景

  1. 01为角色设置行走与攻击动画
  2. 02在状态间平滑切换动画
  3. 03在动画帧触发命中框或音效
  4. 04为 3D 角色配置骨骼 IK

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/jame581/godotprompter --skill animation-system

安装后在 Claude Code 中输入/animation-system确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
animation-markers.md
blend-spaces.md
bone-constraints.md
common-pitfalls.md
common-recipes.md
ik-recipes.md
ik-solver-comparison.md
retargeting.md
skeleton-modifiers.md
sprite-animation.md
state-machine-examples.md

详细介绍

Godot 4.3+ 中的动画系统

所有示例均适用于 Godot 4.3+,不使用已弃用的 API。先展示 GDScript,再展示 C#。

**相关技能:**用于管理游戏状态的 state-machine,用于驱动动画的移动功能的 player-controller,用于构建可复用动画组件的 component-system,用于 TileMaps、视差滚动、2D 光照和画布图层组织的 2d-essentials,用于 AnimationTree 和 3D 动画混合的 3d-essentials,用于着色器驱动的受击闪白和溶解效果的 shader-basics,以及用于与关键帧动画并行实现代码驱动运动的 tween-animation。


1. 核心概念

AnimationPlayer 与 AnimationTree
节点用途复杂度说明
AnimationPlayer简单播放、单次效果低直接播放、停止或排队播放单个动画片段
AnimationTree混合、过渡、分层动画中到高使用状态机和混合树实现平滑过渡

**经验法则:**从 AnimationPlayer 开始。当需要在动画之间进行混合(行走/奔跑混合、方向移动、上半身/下半身分层)时,再添加 AnimationTree。

动画工作流
1. Create AnimationPlayer node       → holds all animation clips
2. Add tracks in the Animation panel → keyframe properties, methods, audio
3. (Optional) Add AnimationTree      → blend/transition logic
4. Trigger from code                 → play(), travel(), set parameters

2. AnimationPlayer 基础知识

场景结构
Character (CharacterBody2D)
├── Sprite2D
└── AnimationPlayer

AnimationPlayer 可以为任意兄弟节点或子节点上的任何属性制作动画:精灵帧、调制、位置、旋转、缩放、可见性、碰撞形状的禁用状态、方法调用(Call Method 轨道)、音频播放(Audio Playback 轨道)。

GDScript — 基本播放
extends CharacterBody2D

@onready var anim_player: AnimationPlayer = $AnimationPlayer

func _physics_process(delta: float) -> void:
    var input_dir := Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")

    if input_dir != Vector2.ZERO:
        velocity = input_dir * 200.0
        anim_player.play("walk")
    else:
        velocity = Vector2.ZERO
        anim_player.play("idle")

    move_and_slide()
C# — 基本播放
using Godot;

public partial class Character : CharacterBody2D
{
    private AnimationPlayer _animPlayer;

    public override void _Ready()
    {
        _animPlayer = GetNode<AnimationPlayer>("AnimationPlayer");
    }

    public override void _PhysicsProcess(double delta)
    {
        Vector2 inputDir = Input.GetVector("ui_left", "ui_right", "ui_up", "ui_down");

        if (inputDir != Vector2.Zero)
        {
            Velocity = inputDir * 200.0f;
            _animPlayer.Play("walk");
        }
        else
        {
            Velocity = Vector2.Zero;
            _animPlayer.Play("idle");
        }

        MoveAndSlide();
    }
}

如果动画已经在播放时调用 play() 并传入相同的动画名称,则不会有任何效果(不会重新开始)。每帧调用都是安全的。

播放控制
anim_player.play("attack")
anim_player.play_backwards("attack")
anim_player.queue("idle")            # play after current
anim_player.stop()
anim_player.pause()
anim_player.play()                   # resume from paused position
anim_player.speed_scale = 2.0
anim_player.seek(0.5)
_animPlayer.Play("attack");
_animPlayer.PlayBackwards("attack");
_animPlayer.Queue("idle");
_animPlayer.Stop();
_animPlayer.Pause();
_animPlayer.Play();
_animPlayer.SpeedScale = 2.0f;
_animPlayer.Seek(0.5);

3. 动画信号

func _ready() -> void:
    anim_player.animation_finished.connect(_on_animation_finished)

func _on_animation_finished(anim_name: StringName) -> void:
    match anim_name:
        "attack":
            anim_player.play("idle")
        "death":
            queue_free()
public override void _Ready()
{
    _animPlayer = GetNode<AnimationPlayer>("AnimationPlayer");
    _animPlayer.AnimationFinished += OnAnimationFinished;
}

private void OnAnimationFinished(StringName animName)
{
    if (animName == "attack")
        _animPlayer.Play("idle");
    else if (animName == "death")
        QueueFree();
}
方法调用轨道

添加 Call Method 轨道,在动画的精确帧触发游戏逻辑(在第 5 帧生成投射物、在命中帧播放音效、挥击期间启用命中框)。在 Animation 面板中:Add Track → Call Method Track → 选择目标节点 → 添加关键帧 → 设置方法名称和参数。

func spawn_projectile() -> void:
    var bullet := preload("res://scenes/bullet.tscn").instantiate()
    get_parent().add_child(bullet)
    bullet.global_position = $Muzzle.global_position

func enable_hitbox() -> void:
    $HitboxArea/CollisionShape2D.disabled = false

4. 精灵帧动画

2D 角色动画有两种实现方式:AnimatedSprite2D(快速实现,仅支持帧动画)和 AnimationPlayer + Sprite2D(完整的属性动画)。简单角色可选用 AnimatedSprite2D;如果还需要同步为命中框、粒子、音效或其他属性制作动画,则使用 AnimationPlayer。

完整的 GDScript 和 C# 示例(通过 Input.get_vector 和 flip_h 驱动的 CharacterBody2D 行走动画)请参阅 references/sprite-animation.md。

往返播放(Godot 4.7+)

SpriteFrames 使用 set_animation_loop_mode(anim, SpriteFrames.LOOP_PINGPONG)(也可使用 LOOP_NONE、LOOP_LINEAR)替代布尔值 set_animation_loop()(已弃用);适用于 AnimatedSprite2D 和 AnimatedSprite3D。

GDScript 和 C# 代码片段请参阅 references/sprite-animation.md。


5. AnimationTree — 标准状态机

场景结构
Character (CharacterBody2D)
├── Sprite2D
├── AnimationPlayer        ← holds all clips
└── AnimationTree          ← controls blending/transitions
    (tree_root = AnimationNodeStateMachine or AnimationNodeBlendTree)

**设置:**将 AnimationTree 添加为 AnimationPlayer 的兄弟节点。将 anim_player 设置为指向 AnimationPlayer。将 active = true。选择根节点:AnimationNodeStateMachine(带过渡的离散状态)或 AnimationNodeBlendTree(连续混合)。

状态机播放

典型模式:从 anim_tree["parameters/playback"] 缓存 AnimationNodeStateMachinePlayback,在游戏逻辑代码中调用 travel("state")(travel() 会平滑过渡;start() 会立即切换),并通过 get_current_node() 查询当前活动状态。

完整的 GDScript 和 C# CharacterBody2D 示例,请参阅 references/state-machine-examples.md。

混合树 — BlendSpace1D / BlendSpace2D

如需连续混合(根据速度在步行↔跑步之间切换,或根据 2D 向量实现 4/8 方向移动),请将根节点设为 AnimationNodeBlendTree,添加 BlendSpace1D 或 BlendSpace2D,并在每帧通过游戏逻辑代码设置 anim_tree["parameters/BlendSpace2D/blend_position"]。

关于混合点的放置,以及驱动 1D 速度混合和 2D 方向混合的 GDScript + C# 代码,请参阅 references/blend-spaces.md。

命名混合点(Godot 4.7+)

add_blend_point() 新增了可选的 name 参数(请传入名称:空名称将被弃用);使用 find_blend_point_by_name() 查找混合点。

GDScript + C# 代码片段请参阅 references/blend-spaces.md。

⚠️ Godot 4.7 中的变更: AnimationNodeBlendSpace1D/2D 中的 bool sync 已弃用,现由 sync_mode 属性(C#:SyncMode)取代。该属性接受以下枚举值:SYNC_MODE_NONE(默认值——非活动动画会冻结)、SYNC_MODE_INDEPENDENT(旧版 sync = true)、SYNC_MODE_CYCLIC_MUTABLE、SYNC_MODE_CYCLIC_CONSTANT。如果在 4.6 中能正常混合的树不再正确过渡,请为每个混合空间设置 sync_mode。完整的枚举语义说明:references/blend-spaces.md。


6. 骨骼修改器(3D,4.4+)

LookAtModifier3D(Godot 4.4+)

以程序化方式旋转骨骼,使其朝向世界空间中的目标。适用于头部追踪和眼神接触,无需额外的动画片段。

带角度限制和影响混合的完整 GDScript 和 C# 示例,请参阅 references/skeleton-modifiers.md。

⚠️ Godot 4.7 中的变更: LookAtModifier3D.relative 的默认值为 false(相对于静止姿势旋转);只有 4.6.0 使用 true。设置 relative = true 可恢复原有行为——详情请参阅 references/skeleton-modifiers.md。

BoneConstraint3D(Godot 4.5+)

AimModifier3D、CopyTransformModifier3D 和 ConvertTransformModifier3D 从同一骨架上的另一个骨骼获取参考对象(用于镜像、绑定次级骨架、骨骼间瞄准);从 Godot 4.6 开始,参考对象也可以是 Node3D(REFERENCE_TYPE_NODE)。

完整深入介绍,包括修改器表格、场景结构,以及 AimModifier3D 和 CopyTransformModifier3D 的 GDScript 和 C# 示例,请参阅 references/bone-constraints.md。

SpringBoneSimulator3D(Godot 4.4+)

模拟骨骼上的弹簧物理效果——头发、披风、尾巴和天线会以程序化方式弹跳和摇摆。将其添加为 Skeleton3D 的子节点,然后在检查器中配置弹簧链(根骨骼、末端骨骼、半径、刚度、阻力、重力)。

属性参考表,以及针对不同用途(头发、天线、披风)的推荐起始值,请参阅 references/skeleton-modifiers.md。

动画标记(Godot 4.4+)

片段内的命名点或区域(时间轴 → 插入标记……),可用于子区域循环和帧级精确事件,无需拆分片段;使用 play_section_with_markers() 播放某个区域。

工作流和 GDScript + C# 代码请参阅 references/animation-markers.md。

动画重定向(Godot 4.3+)

Godot 4.3 会在导入 .glb/.gltf 时,通过 SkeletonProfile(例如 SkeletonProfileHumanoid)将动画从一个骨架重定向到另一个骨架。之后,动画会以通用配置文件骨骼名称为目标,因此任何匹配的骨架都能播放这些动画。

完整的导入停靠面板设置步骤,请参阅 references/retargeting.md。


7. IKModifier3D — 求解器对比(Godot 4.6+)

Godot 4.6 新增了 IKModifier3D,这是骨骼 IK 求解器的基类,并提供五种可直接使用的求解器:TwoBoneIK3D、CCDIK3D、FABRIK3D、JacobianIK3D 和 SplineIK3D。这些都是 Skeleton3D 的 SkeletonModifier3D 子节点,可与其他修改器(例如 LookAtModifier3D)协同工作。

根据骨骼链选择:TwoBoneIK3D 适用于恰好由两根骨骼组成的肢体(需要一个极向节点),FABRIK3D 适用于没有关节限制的简单骨骼链,CCDIK3D 适用于关节有限制的情况,SplineIK3D 用于沿 Path3D 移动,JacobianIK3D 则适合平滑、有机的动作,但跟踪速度较慢。

完整的求解器对比表和选择指南,请参阅 references/ik-solver-comparison.md。

完整的 GDScript 和 C# 示例,包括带影响权重混合的手臂伸展(CCDIK3D)、不平坦地形上的脚部放置(FABRIK3D + 射线检测),以及基础 FABRIK 手臂 IK 设置,请参阅 references/ik-recipes.md。


8. 常用示例

两个贴近游戏玩法的动画示例:受击闪白调制补间,以及使用 AnimationPlayer 的 Call Method 轨道实现带缓冲的攻击连招。

完整的 GDScript 和 C# 代码(受击闪白、带连招窗口缓冲的攻击连招),请参阅 references/common-recipes.md。


9. 常见问题

快速症状 → 原因 → 修复表,涵盖动画突然跳变而非平滑混合、AnimationTree 未激活、travel() 未发生状态切换、轨道节点路径错误、Call Method 轨道无响应、混合参数无效,以及每帧调用 play() 导致的重置。

完整表格请参阅 references/common-pitfalls.md。


10. 实现检查清单

  • AnimationPlayer 是动画节点的直接子节点(没有更深层的嵌套)
  • 所有动画轨道节点路径均有效(场景结构调整后没有失效引用)
  • AnimationTree 的 active 已设为 true,且 anim_player 指向正确的 AnimationPlayer
  • 状态机转换设置了合适的淡入淡出时间(响应迅速的游戏玩法建议使用 0.1–0.2s)
  • 循环动画(待机、行走、跑步)在 Animation 面板中将循环模式设为 Loop
  • 单次播放动画(攻击、跳跃、死亡)将循环模式设为 None
  • 使用 Call Method 轨道处理游戏事件(启用/禁用命中框、生成投射物、播放音效)
  • 每帧都从游戏玩法代码设置混合参数(而不只是在状态变化时设置)
  • 需要后续逻辑的单次播放动画已连接 animation_finished 信号
  • 头部/眼部跟踪使用 LookAtModifier3D,而非手动旋转骨骼(Godot 4.4+)
  • 头发、披风和尾巴使用 SpringBoneSimulator3D,而非自定义物理脚本(Godot 4.4+)
  • 共享动画库使用 SkeletonProfileHumanoid 进行重定向(Godot 4.3+)
  • 骨骼间瞄准/复制约束使用 AimModifier3D / CopyTransformModifier3D,而非手动编写骨骼变换代码(Godot 4.5+)
  • 手臂/腿部 IK 使用 IKModifier3D 子类(两骨骼肢体使用带极向节点的 TwoBoneIK3D,较长的骨骼链使用 FABRIK3D 或 CCDIK3D),而非自定义 IK 脚本(Godot 4.6+)

评论

支持 Markdown