mcpField
U
unity-animation

unity-animation

github.com/nice-wolf-studioクリエイティブ・メディア4077 回インストール6 週間前に更新
リポジトリ

unity-animation について

Mecanim、Animator Controller、Blend Tree、Timeline、アニメーションスクリプトを扱うUnity開発者向けのスキルです。設定手順とコード例で、各コンポーネントとワークフローを説明します。

主な機能

  1. 01Mecanimの構成要素とアニメーション種別
  2. 02Animatorの状態・遷移・パラメーター
  3. 03Blend Treeの設定
  4. 04Avatarの設定とリターゲティング
  5. 05Root Motionとアニメーションイベント
  6. 06Timelineとアニメーションスクリプト

活用シーン

  1. 01キャラクターの移動と状態遷移の構築
  2. 02Humanoidリグ間でのアニメーション転送
  3. 03再生中のアニメーションイベント発火
  4. 04Timelineによるシネマティックシーケンス作成

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/nice-wolf-studio/unity-claude-skills --skill unity-animation

インストール後、Claude Code で/unity-animationを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
animation-clips.md
animator-controller.md
timeline.md

詳細

Unity のアニメーションシステム

アニメーションシステムの概要

Unity の Mecanim アニメーションシステムは、相互に連携する次の 3 つのコンポーネントを基盤としています。

  1. アニメーションクリップ -- 動作の単位(待機、歩行、走行)
  2. Animator Controller -- クリップを状態と遷移のフローチャートに整理するステートマシン
  3. Avatar システム -- リターゲティング用に、ヒューマノイドキャラクターのスケルトンを共通の内部形式にマッピングします

Animator コンポーネントは GameObject にアタッチされ、再生に必要な Animator Controller と Avatar アセットの両方を参照します。

アニメーションの種類
  • Humanoid -- Avatar の設定が必要です。異なるキャラクターリグ間のリターゲティングをサポートします。Generic より CPU 負荷が 15~20% 高くなります
  • Generic -- 特定の階層にある Transform または MonoBehaviour のプロパティをアニメーション化します。異なる階層間では転用できません
  • Legacy -- 古い Animation コンポーネントです。シンプルな単発アニメーションや UI アニメーションに使用します

Animator Controller

Animator Controller アセットは、キャラクターまたはアニメーション化された GameObject 用の Animation Clip と Transition をまとめます。

作成方法: Project ウィンドウで右クリック > Create > Animator Controller

主なコンポーネント
  • State -- 各ステートは、関連付けられた Animation Clip または Blend Tree を再生します
  • Transition -- ステートマシンがステート間を切り替える方法とタイミングを定義します
  • Parameter -- スクリプトから設定して遷移を制御する変数(Float、Int、Bool、Trigger)です
  • Layer -- 異なる身体部位やアニメーションの目的に応じて、ステートマシンを分けます
  • Sub-State Machine -- 階層的に整理するための、ネストされたステートマシンです
パラメーター

使用できる種類は 4 つです。

種類説明スクリプトメソッド
Float小数SetFloat() / GetFloat()
Int整数SetInteger() / GetInteger()
Bool真/偽SetBool() / GetBool()
Trigger自動リセットされるブール値SetTrigger() / ResetTrigger()
using UnityEngine;

public class PlayerAnimController : MonoBehaviour
{
    Animator animator;

    void Start()
    {
        animator = GetComponent<Animator>();
    }

    void Update()
    {
        // Note: Uses legacy Input Manager for simplicity. See unity-input for the new Input System.
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");
        bool fire = Input.GetButtonDown("Fire1");

        animator.SetFloat("Forward", v);
        animator.SetFloat("Strafe", h);
        animator.SetBool("Fire", fire);
    }

    void OnCollisionEnter(Collision col)
    {
        if (col.gameObject.CompareTag("Enemy"))
        {
            animator.SetTrigger("Die");
        }
    }
}
Animator Override Controller

Animator Controller の構造、パラメーター、ロジックを維持したまま、アニメーションクリップを置き換えます。同じステートマシンを共有しながら、異なるクリップを使用する複数のキャラクターに便利です。

重要: Override Controller を使用する場合は、遷移の終了時間を秒ではなく正規化時間で設定してください。オーバーライドするクリップの長さが異なると、終了時間が無視されることがあります。

レイヤー
  • Override モード -- 前のレイヤーのアニメーションを置き換えます
  • Additive モード -- 前のレイヤーのアニメーションに重ねてアニメーションを追加します
  • Avatar Mask -- レイヤーの適用対象を特定の身体部位(例:上半身のみ)に制限します
  • Synced Layers -- 異なるクリップでステートマシンの構造を再利用します

ステートマシンと遷移

ステート

Animator Controller の各ステートは、個別の動作を表します。特殊なステートには、次のものがあります。

  • Entry -- デフォルトの開始点
  • Any State -- 現在のステートにかかわらず遷移します
  • Exit -- 現在のステートマシンまたはサブステートマシンを終了します
遷移

遷移は、ステート間のブレンド方法を定義します。

設定説明
Has Exit Time正規化時間(例:0.75 = 75% 完了)で遷移を開始します
Transition Durationブレンド期間です。秒単位(Fixed Duration)または遷移元ステートに対する割合で指定します
Transition Offset遷移先ステートの再生開始位置です(0.5 = 中間地点)
Conditionsパラメーターに基づくルールです。すべてを同時に満たす必要があります
Interruption Source遷移を中断できる対象です。None、Current State、Next State、またはそれらの組み合わせを指定します
Ordered Interruption遷移の判定を現在の遷移で停止するか、有効な遷移が見つかるまで続けるかを指定します

Has Exit Time と Conditions の両方が設定されている場合、Unity は終了時間に達した後にのみ条件を確認します。

ステートマシンの動作

StateMachineBehaviour を継承するスクリプトをステートにアタッチします。コールバック:OnStateEnter、OnStateUpdate、OnStateExit、OnStateMove、OnStateIK。すべて (Animator animator, AnimatorStateInfo stateInfo, int layerIndex) を受け取ります。

public class AttackState : StateMachineBehaviour
{
    public AudioClip attackSound;
    override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        AudioSource.PlayClipAtPoint(attackSound, animator.transform.position);
    }
    override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        // Cleanup when leaving state
    }
}

ブレンドツリー

ブレンドツリーは、パラメーター値に基づいて複数の類似したアニメーションを滑らかにブレンドします。時間をかけて個別のステート間を切り替えるトランジションとは異なります。

重要な要件: アニメーションの性質とタイミングが類似している必要があります。接地する足の位置が正規化時間上で揃っている必要があります(例:左足が 0.0、右足が 0.5)。

ブレンドタイプ
  • 1D -- 1 つのパラメーターでブレンドを制御します(例:歩行/走行の速度)
  • 2D Simple Directional -- 2 つのパラメーターを使い、各方向に 1 つのモーションを設定します
  • 2D Freeform Directional -- 2 つのパラメーターを使い、各方向に複数のモーションを設定します
  • 2D Freeform Cartesian -- 2 つのパラメーターを使い、方向を表さないモーションを設定します
  • Direct -- 各モーションに独自のウェイトパラメーターを設定します(表情アニメーション)

作成方法: Animator Controller 内で右クリックし、Create State > From New Blend Tree を選択します。ダブルクリックしてグラフを開きます。Inspector から子モーションを追加します。

// Driving a locomotion blend tree from script
void Update()
{
    float speed = new Vector3(rb.velocity.x, 0, rb.velocity.z).magnitude;
    float direction = Vector3.SignedAngle(transform.forward,
        rb.velocity.normalized, Vector3.up);

    animator.SetFloat("Speed", speed, 0.1f, Time.deltaTime);
    animator.SetFloat("Direction", direction, 0.1f, Time.deltaTime);
}

アバターとヒューマノイドリグ

Avatar システムは、モデルをヒューマノイドとして認識し、アニメーションのリターゲティング用に身体の各部位をマッピングします。

主な概念
  • Avatar -- 骨格構造を Unity 内部のヒューマノイド形式にマッピングします
  • リターゲティング -- 同じ Avatar マッピングを共有する異なるヒューマノイドリグ間でアニメーションを転送します
  • 筋肉の定義 -- ボーン空間ではなく筋肉空間で直感的に制御します
設定
  1. Project ウィンドウでモデルを選択します
  2. Import Settings の Rig タブで、Animation Type を Humanoid に設定します
  3. Avatar のマッピングを設定します(可能な場合、Unity が自動でマッピングします)
  4. Avatar Configuration ウィンドウでボーンの割り当てを確認し、調整します

ルートモーション

ルートモーションは、アニメーションによる移動を GameObject の Transform に反映します。

アーキテクチャ
  • Body Transform -- キャラクターの重心で、ワールド空間のカーブを保持します
  • Root Transform -- Body Transform を Y 平面に投影したもので、実行時に各フレームで計算されます
クリップの Inspector 設定
設定目的
Bake Into Pose (Rotation)向きをボディに保持し、GameObject に回転を適用しません
Bake Into Pose (Y)垂直方向の動きをボディに保持します。ジャンプ以外では有効にします
Bake Into Pose (XZ)水平方向の動きをボディに保持します。アイドルクリップではドリフト防止のため有効にします
Based UponBody Orientation(モーションキャプチャ)、Original(キーフレーム)、Feet(浮き上がりを防止)

Animator.gravityWeight は Bake Into Pose Position Y によって制御されます。有効の場合は 1、無効の場合は 0 です。

// Custom root motion handling
using UnityEngine;

[RequireComponent(typeof(Animator))]
public class RootMotionController : MonoBehaviour
{
    Animator animator;
    CharacterController controller;

    void Start()
    {
        animator = GetComponent<Animator>();
        controller = GetComponent<CharacterController>();
        animator.applyRootMotion = false; // We handle it manually
    }

    void OnAnimatorMove()
    {
        // Apply root motion through CharacterController
        Vector3 deltaPosition = animator.deltaPosition;
        deltaPosition.y -= 9.81f * Time.deltaTime; // Add gravity
        controller.Move(deltaPosition);
        transform.rotation *= animator.deltaRotation;
    }
}

アニメーションイベント

アニメーションイベントは、アニメーションタイムライン上の指定した位置で関数を呼び出します。

パラメーターの種類
  • Float -- 数値(例:音量)
  • Int -- 整数値
  • String -- テキストデータ
  • Object -- GameObject または Prefab の参照
設定
  1. Animation タブで Events セクションを展開します
  2. 再生ヘッドを目的のフレームに移動します
  3. Add Event をクリックします
  4. アタッチされたスクリプトのメソッド名と一致する Function 名を設定します
using UnityEngine;

public class FootstepHandler : MonoBehaviour
{
    public AudioClip[] footstepSounds;
    public GameObject dustPrefab;

    // Called by animation event -- function name must match event
    public void PlayFootstep(int footIndex)
    {
        if (footstepSounds.Length > 0)
        {
            int clipIndex = Random.Range(0, footstepSounds.Length);
            AudioSource.PlayClipAtPoint(footstepSounds[clipIndex], transform.position);
        }
    }

    // Called by animation event passing an Object parameter
    public void SpawnEffect(Object effectPrefab)
    {
        Instantiate((GameObject)effectPrefab, transform.position, Quaternion.identity);
    }
}

Timeline

Timeline は、シネマティックコンテンツ、ゲームプレイシーケンス、オーディオシーケンス、パーティクルエフェクトを作成します。パッケージ:com.unity.timeline(v1.8.11、Unity 6.3 対応)。

主なコンポーネント
  • Timeline Asset -- トラック、クリップ、およびその配置を定義します
  • Timeline Instance -- 特定のシーンオブジェクトにバインドされた実行時インスタンスです
  • Playable Director -- Timeline アセットを再生し、トラックをシーンオブジェクトにバインドするコンポーネントです
トラックの種類
トラック目的
Animationバインドされた GameObject の Animator を制御します
Audioバインドされた AudioSource で AudioClip を再生します
Activationバインドされた GameObject を有効化/無効化します
SignalSignalReceiver を介して特定の時刻にイベントを発生させます
Controlサブ Timeline、パーティクルシステム、または他の Playable Director を起動します
PlayablePlayables API を使用するカスタムトラックです
機能
  • タイムラインでのアニメーションの直接記録
  • ヒューマノイドアニメーションのサポート
  • アニメーションオーバーライドトラック
  • モジュール式の構成に対応したサブタイムライン

アニメーションのスクリプト制御

逆運動学(IK)

要件:ヒューマノイドアバター、レイヤーで IK Pass が有効になっていること。

using UnityEngine;

public class IKController : MonoBehaviour
{
    Animator animator;
    public bool ikActive = true;
    public Transform rightHandTarget;
    public Transform lookTarget;

    void Start()
    {
        animator = GetComponent<Animator>();
    }

    void OnAnimatorIK()
    {
        if (animator == null || !ikActive) return;

        // Look at target
        animator.SetLookAtWeight(1f);
        animator.SetLookAtPosition(lookTarget.position);

        // Right hand IK
        animator.SetIKPositionWeight(AvatarIKGoal.RightHand, 1f);
        animator.SetIKRotationWeight(AvatarIKGoal.RightHand, 1f);
        animator.SetIKPosition(AvatarIKGoal.RightHand, rightHandTarget.position);
        animator.SetIKRotation(AvatarIKGoal.RightHand, rightHandTarget.rotation);
    }
}
ステートの直接再生
// Play state immediately
animator.Play("Attack");

// Play with normalized time offset (start at 50%)
animator.Play("Attack", 0, 0.5f);

// Crossfade into state over 0.25 seconds
animator.CrossFadeInFixedTime("Run", 0.25f);

// Crossfade using normalized time
animator.CrossFade("Run", 0.1f);
ステート情報の照会
AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(0);

if (stateInfo.IsName("Attack"))
{
    Debug.Log("Currently attacking");
}

if (stateInfo.normalizedTime >= 1.0f && !animator.IsInTransition(0))
{
    Debug.Log("Animation finished");
}

// Use hash for performance
int runHash = Animator.StringToHash("Run");
if (animator.HasState(0, runHash))
{
    animator.Play(runHash);
}
ターゲットマッチング
// Match character's hand to a ledge position during climb animation
animator.MatchTarget(ledgePosition, Quaternion.identity, AvatarTarget.RightHand,
    new MatchTargetWeightMask(Vector3.one, 0f), 0.1f, 0.4f);

よく使われるパターン

キャラクターの移動コントローラー
using UnityEngine;

[RequireComponent(typeof(Animator))]
public class LocomotionController : MonoBehaviour
{
    Animator animator;
    static readonly int SpeedHash = Animator.StringToHash("Speed");
    static readonly int GroundedHash = Animator.StringToHash("Grounded");
    static readonly int JumpHash = Animator.StringToHash("Jump");

    void Start()
    {
        animator = GetComponent<Animator>();
    }

    void Update()
    {
        float speed = Input.GetAxis("Vertical");
        animator.SetFloat(SpeedHash, Mathf.Abs(speed), 0.1f, Time.deltaTime);
        animator.SetBool(GroundedHash, IsGrounded());

        if (Input.GetButtonDown("Jump") && IsGrounded())
        {
            animator.SetTrigger(JumpHash);
        }
    }

    bool IsGrounded()
    {
        return Physics.Raycast(transform.position + Vector3.up * 0.1f, Vector3.down, 0.2f);
    }
}
実行時のオーバーライドコントローラーの切り替え
using UnityEngine;

public class WeaponAnimSwap : MonoBehaviour
{
    public AnimatorOverrideController swordOverride;
    public AnimatorOverrideController bowOverride;
    Animator animator;

    void Start()
    {
        animator = GetComponent<Animator>();
    }

    public void EquipSword()
    {
        animator.runtimeAnimatorController = swordOverride;
    }

    public void EquipBow()
    {
        animator.runtimeAnimatorController = bowOverride;
    }
}

アンチパターン

アンチパターン問題解決策
毎フレーム文字列パラメーターを使用するGC の割り当てが発生し、検索が遅くなりますAnimator.StringToHash() でハッシュをキャッシュします
非ヒューマノイドオブジェクトにヒューマノイドリグを使用するCPU に 15~20% の不要な負荷がかかります小道具、動物、エフェクトには Generic アニメーションタイプを使用します
共有ルートの下に複数の Animator を配置する階層ごとの単一スレッド書き込み制限により、並列処理が妨げられます各 Animator に独自のルート GameObject を割り当てます
StateMachineBehaviour を多用する同期ポイントが発生し、並列評価が妨げられますSMB コールバックを最小限にし、スクリプト側のロジックを優先します
Animator 経由で RectTransform をアニメーション化する書き込みの決定性に関する問題が発生しますUI アニメーションには旧式の Animation コンポーネントを使用します
単発アニメーションに複雑なステートマシンを使用するアイドル中も遷移評価が継続します代わりに Animation コンポーネントまたは Playables API を使用します
Animator.Update() を手動で呼び出す並列実行が回避されます並列処理を維持したまま手動制御するには PlayableGraph を使用します
遷移の終了時間を正規化された値に設定しないOverride Controller のクリップで遷移がスキップされることがあります終了時間には必ず正規化時間を使用します
コントローラーの切り替え後に Rebind() を呼び出し忘れるバインディングが古いままになり、再生が正しく行われません実行時にコントローラーを変更する際は Rebind() を呼び出します
アイドルクリップで Bake Into Pose が無効(XZ)になっているアイドルアニメーションでドリフトが蓄積します静止クリップでは Bake Into Pose XZ を有効にします

主要 API クイックリファレンス

Animator -- 主要プロパティ

applyRootMotion、speed、updateMode(Normal/AnimatePhysics/UnscaledTime)、cullingMode、deltaPosition、deltaRotation、velocity、isHuman、layerCount、bodyPosition、gravityWeight

Animator -- 主要メソッド
  • 再生: Play(state, layer, time)、CrossFade(state, duration)、CrossFadeInFixedTime(state, duration)
  • パラメーター: SetFloat/Int/Bool/Trigger(name, value)、GetFloat/Int/Bool(name)、ResetTrigger(name)
  • ステートの照会: GetCurrentAnimatorStateInfo(layer)、GetNextAnimatorStateInfo(layer)、IsInTransition(layer)
  • IK: SetIKPosition/Rotation(goal, value)、SetIKPositionWeight/RotationWeight(goal, weight)、SetLookAtPosition(pos)
  • ユーティリティ: MatchTarget(...)、GetBoneTransform(bone)、Rebind()、StringToHash(name)、SetLayerWeight(layer, weight)

関連スキル

  • unity-foundations -- Unity の基本概念、GameObject、コンポーネント、プロジェクト構成
  • unity-scripting -- MonoBehaviour のライフサイクル、C# のパターン、イベントシステム
  • unity-graphics -- レンダリング、マテリアル、シェーダー(アニメーション化されたマテリアルプロパティに関連)

Additional Resources

コメント