Animator Controller
Animator Controller là state machine trực quan quản lý Animation Clip — quyết định khi nào và cách nào blend Idle, Walk, Run, Jump, Attack và mọi state khác.
Hãy tưởng tượng...
Animator Controller giống như bộ não phối hợp diễn xuất của nhân vật. Nó biết nhân vật đang ở trạng thái nào (đứng, chạy, nhảy) và khi điều kiện được thoả mãn (bấm nút nhảy, tốc độ > 0) thì chuyển sang animation tiếp theo một cách mượt mà. Bạn khai báo các "State" là các clip hoạt hình và vẽ "mũi tên" (Transition) giữa chúng với điều kiện — Animator Controller tự quyết định khi nào kích hoạt từng mũi tên.
Khái niệm chi tiết
Animator Controller là asset
(.controller)
chứa một hoặc nhiều Layer, mỗi layer là một state machine độc lập. Layer Base
thường chứa locomotion (di chuyển), layer trên có thể blend override cho body upper (ném đạn
trong khi chạy). Mỗi layer có Weight (0–1) và Blending Mode
(Override/Additive).
Trong mỗi layer, có các State (hộp cam/xanh) đại diện cho Animation Clip, và
Transition (mũi tên) định nghĩa điều kiện chuyển state. Transition có
Has Exit Time
(đợi animation xong rồi mới chuyển) và
Transition Duration
(thời gian blend giữa hai clip). Parameters (Int, Float, Bool, Trigger) là các
biến Animator đọc để quyết định transition nào được kích hoạt.
Sub-State Machine là cách nhóm nhiều state phức tạp thành một node (ví dụ: nhóm tất cả attack variants vào “Combat” sub-state). Any State là state đặc biệt — transition từ Any State sẽ kích hoạt từ bất kỳ state hiện tại nào, dùng cho Death hoặc Hit animation cần interrupt.
Từ Unity 2022+, Animation Rigging package cho phép IK layer trên Animator Controller: điều chỉnh runtime vị trí tay/chân (VR controllers, leo tường) mà không cần Animation Clip riêng.
Sơ đồ State Machine nhân vật cơ bản
Hướng dẫn thực hành
Tạo Animator Controller
Project → Create → Animator Controller. Double-click để mở Animator window. Kéo Animation Clip vào để tạo State.
Thêm Parameters
Animator window → Parameters tab (+) → thêm Float "Speed", Bool "IsGrounded", Trigger "Jump". Đây là biến C# sẽ set.
Tạo Transition với điều kiện
Chuột phải State → Make Transition → click State đích. Chọn Transition → Inspector → Conditions → thêm điều kiện (Speed > 0.1).
Gán vào GameObject
Add Component → Animator → gán Controller vào slot "Controller". Đảm bảo Avatar đúng (Humanoid setup).
Drive từ script
animator.SetFloat("Speed", velocity.magnitude) trong Update(). Dùng Animator.StringToHash() để cache hash thay vì string.
Trình mô phỏng tương tác
Click vào state để chuyển trực tiếp, hoặc dùng nút điều khiển để trigger transition có điều kiện.
Ví dụ Code
Cơ bảnDrive Animator parameters từ PlayerController — locomotion cơ bản với Speed và Jump trigger.
using UnityEngine;
public class AnimatorDriver : MonoBehaviour
{
Animator anim;
// Cache hash tại Awake — nhanh hơn string mỗi 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 tự reset sau 1 frame
}
public void Die()
{
anim.SetTrigger(DeathHash);
anim.SetLayerWeight(1, 0f); // Tắt layer 1 khi chết
}
}Ví dụ Code
Nâng caoPlayInFixedTime, CrossFade và đọc state hiện tại — kiểm soát chi tiết transition từ code.
using UnityEngine;
public class AdvancedAnimator : MonoBehaviour
{
Animator anim;
static readonly int BaseLayer = 0;
void Awake() => anim = GetComponent<Animator>();
// CrossFade: chuyển sang state theo tên với blend duration tuỳ chỉnh
public void PlayAttack(string attackName)
{
anim.CrossFadeInFixedTime(attackName, 0.15f, BaseLayer);
}
// Kiểm tra nhân vật đang ở state cụ thể (tên state hoặc tag)
bool IsInState(string stateName)
{
return anim.GetCurrentAnimatorStateInfo(BaseLayer)
.IsName(stateName);
}
// Điều chỉnh tốc độ phát animation theo gameplay
public void SetAttackSpeed(float speedMultiplier)
{
anim.SetFloat("AttackSpeed", speedMultiplier);
}
// Đọc normalized time để biết animation đã phát được bao nhiêu %
void Update()
{
var info = anim.GetCurrentAnimatorStateInfo(BaseLayer);
if (info.normalizedTime >= 0.9f && info.IsTag("Attack"))
{
Debug.Log("Attack sắp kết thúc — có thể combo");
}
}
}📌 Ghi nhớ nhanh
- ▸Trigger tự reset sau 1 frame (dùng cho Jump, Hit)
- ▸Animator.StringToHash() → cache ở Awake, tránh string GC
- ▸Any State → transition interrupt bất kỳ state nào
- ▸SetFloat(hash, value, damping, dt) để blend mượt hơn
- ▸normalizedTime: 0 = đầu clip, 1 = cuối clip
⚠️ Lỗi thường gặp
❌ Trigger không hoạt động — state không chuyển
Has Exit Time = true và animation chưa xong — trigger bị ignore
✅ Tắt Has Exit Time cho transition muốn trigger bất kỳ lúc nào
❌ Animation không blend mượt — cắt đột ngột
Transition Duration = 0
✅ Đặt Transition Duration = 0.1–0.25s để blend