Animator Controller
Animator Controller は Animation Clip を管理する視覚的なステートマシンです。Idle・Walk・Run・Jump・Attack など各状態の切替とブレンドを決め、Parameters と Transition で滑らかに遷移します。図解とシミュレーターで学べます。
想像してみてください...
Animator Controller はキャラクターの舞台監督です。いまどの状態にいるか(idle、run、jump)を把握し、条件が満たされると(ジャンプボタン、speed > 0)次のクリップへ滑らかに遷移します。State をクリップとして置き、条件付きの「矢印」(Transition)を描くと、コントローラが自動で発火します。
概念の詳細
Animator Controller は
(.controller)
アセットで、1 つ以上の Layer を持ちます。各 Layer は独立したステートマシンです。Base Layer は通常ロコモーション、上位 Layer は胴体だけ上書き(走りながら投げる)などに使います。各 Layer には Weight(0–1)と Blending Mode
(Override/Additive)があります。
Layer 内では State(オレンジ/緑の箱)が Animation Clip、
Transition(矢印)が切替条件です。Transition には
Has Exit Time
(クリップ終了を待つ)と
Transition Duration
(ブレンド時間)があります。Parameter(Int、Float、Bool、Trigger)は Animator が Transition を選ぶ変数です。
Sub-State Machine は複雑な状態を 1 ノードにまとめます(例: 攻撃バリエーションを “Combat” に)。Any State は特別で、現在どの状態からでも遷移でき、Death や Hit の割り込みに使います。
Unity 2022+ では Animation Rigging パッケージが Animator の上に IK を足し、専用クリップなしで実行時の手/足ポーズ(VR コントローラ、クライミング)を扱えます。
基本的なキャラクターステートマシン
ハンズオン手順
Animator Controller を作成
Project → Create → Animator Controller。ダブルクリックで Animator ウィンドウを開き、Animation Clip をドロップして State を作ります。
Parameter を追加
Animator ウィンドウ → Parameters タブ(+)→ Float "Speed"、Bool "IsGrounded"、Trigger "Jump" を追加。C# からセットする変数です。
条件付き Transition を作成
State を右クリック → Make Transition → 目標をクリック。Transition を選び → Inspector → Conditions → (Speed > 0.1)を追加。
GameObject に割り当て
Add Component → Animator → "Controller" にドロップ。Avatar が正しいか確認(Humanoid セットアップ)。
スクリプトから駆動
Update() で animator.SetFloat("Speed", velocity.magnitude)。文字列の代わりに Animator.StringToHash() でハッシュをキャッシュします。
インタラクティブシミュレーター
状態をクリックしてジャンプするか、コントロールボタンで条件付き Transition を発火してみましょう。
コード例
基本PlayerController から Animator Parameter を駆動——Speed と Jump Trigger による基本ロコモーション。
using UnityEngine;
public class AnimatorDriver : MonoBehaviour
{
Animator anim;
// Cache hashes in Awake — faster than a string every frame
static readonly int SpeedHash = Animator.StringToHash("Speed");
static readonly int JumpHash = Animator.StringToHash("Jump");
static readonly int GroundHash = Animator.StringToHash("IsGrounded");
static readonly int DeathHash = Animator.StringToHash("Death");
void Awake() => anim = GetComponent<Animator>();
void Update()
{
Vector3 vel = GetComponent<Rigidbody>().velocity;
anim.SetFloat(SpeedHash, vel.magnitude, 0.1f, Time.deltaTime);
anim.SetBool(GroundHash, isGrounded);
if (Input.GetKeyDown(KeyCode.Space))
anim.SetTrigger(JumpHash); // Trigger auto-resets after 1 frame
}
public void Die()
{
anim.SetTrigger(DeathHash);
anim.SetLayerWeight(1, 0f); // Disable layer 1 on death
}
}コード例
上級PlayInFixedTime、CrossFade、現在状態の読み取り——コードから細かい遷移を制御。
using UnityEngine;
public class AdvancedAnimator : MonoBehaviour
{
Animator anim;
static readonly int BaseLayer = 0;
void Awake() => anim = GetComponent<Animator>();
// CrossFade: switch to a named state with a custom blend duration
public void PlayAttack(string attackName)
{
anim.CrossFadeInFixedTime(attackName, 0.15f, BaseLayer);
}
// Is the character in a given state (name or tag)
bool IsInState(string stateName)
{
return anim.GetCurrentAnimatorStateInfo(BaseLayer)
.IsName(stateName);
}
// Scale animation playback from gameplay
public void SetAttackSpeed(float speedMultiplier)
{
anim.SetFloat("AttackSpeed", speedMultiplier);
}
// Read normalized time to know how far the clip has played
void Update()
{
var info = anim.GetCurrentAnimatorStateInfo(BaseLayer);
if (info.normalizedTime >= 0.9f && info.IsTag("Attack"))
{
Debug.Log("Attack almost done — combo window");
}
}
}📌 要点
- ▸Trigger は 1 フレーム後に自動リセット(Jump、Hit)
- ▸Animator.StringToHash() → Awake でキャッシュし、文字列 GC を避ける
- ▸Any State → 現在のどの状態からでも割り込み
- ▸SetFloat(hash, value, damping, dt) でより滑らかなブレンド
- ▸normalizedTime: 0 = クリップ開始、1 = クリップ終了
⚠️ よくあるミス
❌ Trigger をセットしても状態が変わらない
Has Exit Time が true でクリップがまだ終わっていない——Trigger が無視される
✅ いつでも発火させたい Transition では Has Exit Time をオフにする
❌ アニメーションがブレンドせず硬直切替になる
Transition Duration = 0
✅ Transition Duration を 0.1–0.25 秒にしてブレンドする