mcpField
U
Unity Animation

Unity Animation

github.com/juliankerignard开发852 次安装31 周前更新
代码仓库

关于 Unity Animation

Unity Animation 是面向 Unity 开发者的动画实现指导技能,涵盖代码与 Animator 集成、IK、Root Motion、Timeline 和 Playables API。它提供将动画与游戏逻辑同步及使用高级动画系统的代码模式。

主要功能

  1. 01集成代码与 Animator Controller
  2. 02使用 Animation Events 同步逻辑
  3. 03配置 Animator Layers 与 Blend Trees
  4. 04应用 IK 和 Root Motion
  5. 05使用 Timeline 与 Playables API

适用场景

  1. 01实现角色移动状态与 Blend Tree 联动
  2. 02在动画关键帧触发攻击或脚步逻辑
  3. 03为角色配置 IK、Root Motion 或局部身体动画

安装

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

$npx skills add https://github.com/juliankerignard/unity-skills --skill unity-animation

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

附带文件references/animation-advanced.md

详细介绍

Unity 动画

此技能的作用

指导在 Unity 中实现高级动画。涵盖代码与 Animator 的集成、IK、Root Motion、Animation Rigging、Timeline、Playables API 和高级混合树。

此技能不止介绍 Animator Controller 的简单配置,还提供可用于生产环境的代码模式,用于通过代码驱动动画、将游戏逻辑与关键帧同步,以及利用高级系统(IK、Playables API、Timeline)。

前提条件

  • Animator Controller 已配置基本状态和过渡
  • Animation clips 已导入(根据情况使用 Humanoid 或 Generic 骨架)
  • (可选) 用于 IK 的 Animation Rigging 包(com.unity.animation.rigging)
  • (可选) 用于过场动画的 Timeline 包(com.unity.timeline)

快速开始

  1. 根据需求选择合适的动画系统(见决策树)
  2. 配置 Animator Controller(状态、过渡、参数)
  3. 与代码集成(缓存哈希、参数、事件)
  4. 使用 IK、高级混合、层进行优化

决策树

Quel systeme d'animation ?
|
+-- Animation simple (porte, plateforme, UI) ?
|   --> Animation component simple (legacy) ou Animator avec 1-2 states
|
+-- Personnage joueur ou ennemi avec etats (idle, run, attack) ?
|   --> Animator Controller + State Machine + code integration
|
+-- Animation cinematique / cutscene ?
|   --> Timeline (PlayableDirector + tracks)
|
+-- Melange dynamique d'animations a runtime ?
|   --> Playables API (mixer custom)
|
+-- IK (personnage regarde/attrape un objet) ?
|   --> Animation Rigging package (Rig Builder + constraints)
|
+-- Besoin de performance extreme (milliers d'entites) ?
    --> DOTS Animation (voir /unity-dots)

分步指南

步骤 1:设置 Animator 并与代码集成
[RequireComponent(typeof(Animator))]
public class CharacterAnimator : MonoBehaviour
{
    private Animator animator;

    // TOUJOURS cacher les hash (evite les string lookups chaque frame)
    private static readonly int SpeedHash = Animator.StringToHash("Speed");
    private static readonly int IsGroundedHash = Animator.StringToHash("IsGrounded");
    private static readonly int JumpTrigger = Animator.StringToHash("Jump");
    private static readonly int AttackTrigger = Animator.StringToHash("Attack");

    private void Awake() => animator = GetComponent<Animator>();

    public void SetSpeed(float speed) => animator.SetFloat(SpeedHash, speed);
    public void SetGrounded(bool grounded) => animator.SetBool(IsGroundedHash, grounded);
    public void TriggerJump() => animator.SetTrigger(JumpTrigger);
    public void TriggerAttack() => animator.SetTrigger(AttackTrigger);
}
步骤 2:动画事件
// Appele depuis un clip d'animation a un keyframe precis
public void OnFootstep()
{
    audioService.PlaySFX(footstepClip);
}

public void OnAttackHit()
{
    // Activer hitbox au bon moment de l'animation
    hitbox.SetActive(true);
}

public void OnAttackEnd()
{
    hitbox.SetActive(false);
}
步骤 3:StateMachineBehaviour(附加到状态的逻辑)
public class AttackState : StateMachineBehaviour
{
    public override void OnStateEnter(
        Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        animator.GetComponent<CombatSystem>().OnAttackStart();
    }

    public override void OnStateExit(
        Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        animator.GetComponent<CombatSystem>().OnAttackEnd();
    }
}
步骤 4:Animator 层(部分身体动画)
// Controle dynamique du poids d'un layer (ex: upper body attack)
private static readonly int UpperBodyLayer = 1;

public void EnableUpperBodyOverride(float weight)
{
    animator.SetLayerWeight(UpperBodyLayer, weight);
}
  • Layer 0:基础层(完整的移动动画)
  • Layer 1:上半身覆盖(攻击、交互),使用 Avatar Mask
  • Layer 2:叠加(呼吸、受击反应)
步骤 5:用于移动的混合树

在 Animator Controller 中:

  • 创建一个 2D Freeform Directional 混合树
  • 参数:MoveX(float)、MoveY(float)
  • 动作:待机(0,0)、向前行走(0,0.5)、向前奔跑(0,1)、向左侧移(-1,0)、向右侧移(1,0)
private static readonly int MoveXHash = Animator.StringToHash("MoveX");
private static readonly int MoveYHash = Animator.StringToHash("MoveY");

public void SetMovement(Vector2 input)
{
    // Smooth damp pour eviter les changements brusques
    animator.SetFloat(MoveXHash, input.x, 0.1f, Time.deltaTime);
    animator.SetFloat(MoveYHash, input.y, 0.1f, Time.deltaTime);
}

严格规则

始终:

  • 使用 Animator.StringToHash 缓存哈希(不要在 Update 中使用字符串)
  • 使用 Animation Events 同步逻辑与动画(不要手动计时)
  • 使用 Animator 层实现部分身体动画(上半身攻击 + 下半身奔跑)
  • 在混合树中使用带阻尼的 SetFloat,实现平滑过渡
  • 在 OnDestroy() 中销毁 PlayableGraph,避免内存泄漏

绝不:

  • 在 Update 中调用 GetComponent<Animator>()——在 Awake 中缓存引用
  • 使用 transition duration = 0,除非是纯逻辑状态机(会导致画面跳变)
  • 启用 Root Motion 时手动修改 transform.position
  • 无故使用 Play() 或 CrossFade()——优先使用 Animator Controller 的过渡

优先选择:

  • 使用 2D Freeform 混合树实现方向性移动
  • 使用子状态机组织复杂的 Animator Controller
  • 使用 Override Controller,以不同动画片段复用状态机
  • 对于新项目,优先使用 Animation Rigging,而非 OnAnimatorIK()

相关技能

  • /unity-code-gen——生成 StateMachineBehaviour 和 Animator 样板代码
  • /proto——使用简单动画快速制作原型
  • /unity-dots——使用 DOTS 动画驱动数千个实体
  • /2d——使用 Sprite Library 和 Sprite Swap 实现 2D 动画

故障排查

问题解决方案
动画不播放检查状态是否可达(已连接过渡),参数是否设置正确
角色滑动/漂浮Root Motion 配置错误——检查 Animator 上的 "Apply Root Motion" 和动画片段的曲线
Blend Tree 卡顿检查动画片段的步频(foot cycle)是否一致。调整 threshold
IK 不起作用检查 Animator Controller 中该 layer 是否启用了 "IK Pass"
Animation Event 未调用方法必须为 public,位于与 Animator 相同的 GameObject 上,并使用正确的签名
过渡被阻止检查过渡条件;如果需要立即过渡,请禁用 "Has Exit Time"
Layer override 不起作用检查该 layer 的 Avatar Mask,以及 weight 是否 > 0
PlayableGraph 泄漏始终在 OnDestroy() 中调用 graph.Destroy()

评论

支持 Markdown