Unity Animation
Ce que fait cette skill
Guider l'implementation d'animations avancees dans Unity. Couvre l'integration code-Animator, IK, Root Motion, Animation Rigging, Timeline, Playables API et blend trees avances.
Cette skill va au-dela de la simple configuration d'Animator Controller : elle fournit les patterns de code production-ready pour piloter les animations depuis le code, synchroniser la logique gameplay avec les keyframes, et exploiter les systemes avances (IK, Playables API, Timeline).
Prerequis
- Animator Controller configure avec les states et transitions de base
- Animation clips importes (Humanoid ou Generic rig selon le cas)
- (Optionnel) Package Animation Rigging (
com.unity.animation.rigging) pour l'IK
- (Optionnel) Package Timeline (
com.unity.timeline) pour les cutscenes
Demarrage rapide
- Choisir le systeme d'animation adapte au besoin (voir arbre de decision)
- Configurer l'Animator Controller (states, transitions, parametres)
- Integrer avec le code (hash caches, parametres, events)
- Affiner avec IK, blending avance, layers
Arbre de decision
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)
Guide etape par etape
Step 1 : Setup Animator + code integration
[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);
}
Step 2 : Animation Events
// 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);
}
Step 3 : StateMachineBehaviour (logique attachee aux states)
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();
}
}
Step 4 : Animator Layers (animations partielles)
// 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 : Base (locomotion complete)
- Layer 1 : Upper Body Override (attaque, interaction) avec Avatar Mask
- Layer 2 : Additive (breathing, hit reactions)
Step 5 : Blend Trees pour la locomotion
Dans l'Animator Controller :
- Creer un Blend Tree 2D Freeform Directional
- Parametres :
MoveX (float), MoveY (float)
- Motions : idle (0,0), walk forward (0,0.5), run forward (0,1), strafe left (-1,0), strafe right (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);
}
Regles strictes
TOUJOURS :
- Cacher les hash avec
Animator.StringToHash (pas de strings dans Update)
- Utiliser les Animation Events pour synchroniser logique et animation (pas de timers manuels)
- Utiliser des Animator Layers pour les animations partielles (upper body attack + lower body run)
- Utiliser
SetFloat avec damping pour des transitions fluides dans les blend trees
- Detruire les
PlayableGraph dans OnDestroy() pour eviter les fuites memoire
JAMAIS :
GetComponent<Animator>() dans Update -- cacher la reference dans Awake
transition duration = 0 sauf pour les state machines purement logiques (cause des snaps visuels)
- Modifier
transform.position manuellement quand Root Motion est actif
- Utiliser
Play() ou CrossFade() sans raison -- preferer les transitions de l'Animator Controller
PREFERER :
- Les Blend Trees 2D Freeform pour le mouvement directionnel
- Les Sub-State Machines pour organiser les Animator Controllers complexes
- Les Override Controllers pour reutiliser une state machine avec des clips differents
- Animation Rigging plutot que
OnAnimatorIK() pour les nouveaux projets
Skills connexes
/unity-code-gen -- generer des StateMachineBehaviour et boilerplate Animator
/proto -- prototyper rapidement avec des animations simples
/unity-dots -- DOTS animation pour des milliers d'entites animees
/2d -- animation 2D avec Sprite Library et Sprite Swap
Troubleshooting
| Probleme |
Solution |
| Animation ne joue pas |
Verifier que le state est atteignable (transitions connectees), que le parametre est set correctement |
| Personnage glisse/flotte |
Root Motion mal configure -- verifier "Apply Root Motion" sur l'Animator et les curves du clip |
| Blend Tree saccade |
Verifier que les clips ont la meme cadence de pas (foot cycle). Ajuster le threshold |
| IK ne fonctionne pas |
Verifier que le layer a "IK Pass" active dans l'Animator Controller |
| Animation Event pas appele |
La methode doit etre publique, sur le meme GameObject que l'Animator, avec la bonne signature |
| Transition bloquee |
Verifier les conditions de transition, desactiver "Has Exit Time" si transition immediate souhaitee |
| Layer override ne marche pas |
Verifier l'Avatar Mask du layer, et que le weight > 0 |
| PlayableGraph leak |
Toujours appeler graph.Destroy() dans OnDestroy() |
1---2name: unity-animation3description: Animation avancee dans Unity : Animator, IK, Root Motion, Timeline, Playables API, Animation Rigging, blend trees. Triggers: /anim, /animation, 'Animator avance', 'IK', 'Root Motion', 'Timeline', 'Playables API', 'Animation Rigging', 'blend tree', 'state machine animation', 'animation events'.4---5
6# Unity Animation
7
8## Ce que fait cette skill
9
10Guider l'implementation d'animations avancees dans Unity. Couvre l'integration code-Animator, IK, Root Motion, Animation Rigging, Timeline, Playables API et blend trees avances.
11
12Cette skill va au-dela de la simple configuration d'Animator Controller : elle fournit les patterns de code production-ready pour piloter les animations depuis le code, synchroniser la logique gameplay avec les keyframes, et exploiter les systemes avances (IK, Playables API, Timeline).
13
14## Prerequis
15
16- **Animator Controller** configure avec les states et transitions de base
17- **Animation clips** importes (Humanoid ou Generic rig selon le cas)
18- **(Optionnel)** Package **Animation Rigging** (`com.unity.animation.rigging`) pour l'IK
19- **(Optionnel)** Package **Timeline** (`com.unity.timeline`) pour les cutscenes
20
21## Demarrage rapide
22
231. Choisir le systeme d'animation adapte au besoin (voir arbre de decision)
242. Configurer l'Animator Controller (states, transitions, parametres)
253. Integrer avec le code (hash caches, parametres, events)
264. Affiner avec IK, blending avance, layers
27
28## Arbre de decision
29
30```
31Quel systeme d'animation ?
32|
33+-- Animation simple (porte, plateforme, UI) ?
34| --> Animation component simple (legacy) ou Animator avec 1-2 states
35|
36+-- Personnage joueur ou ennemi avec etats (idle, run, attack) ?
37| --> Animator Controller + State Machine + code integration
38|
39+-- Animation cinematique / cutscene ?
40| --> Timeline (PlayableDirector + tracks)
41|
42+-- Melange dynamique d'animations a runtime ?
43| --> Playables API (mixer custom)
44|
45+-- IK (personnage regarde/attrape un objet) ?
46| --> Animation Rigging package (Rig Builder + constraints)
47|
48+-- Besoin de performance extreme (milliers d'entites) ?
49 --> DOTS Animation (voir /unity-dots)
50```
51
52## Guide etape par etape
53
54### Step 1 : Setup Animator + code integration
55
56```csharp
57[RequireComponent(typeof(Animator))]
58public class CharacterAnimator : MonoBehaviour
59{
60 private Animator animator;
61
62 // TOUJOURS cacher les hash (evite les string lookups chaque frame)
63 private static readonly int SpeedHash = Animator.StringToHash("Speed");
64 private static readonly int IsGroundedHash = Animator.StringToHash("IsGrounded");
65 private static readonly int JumpTrigger = Animator.StringToHash("Jump");
66 private static readonly int AttackTrigger = Animator.StringToHash("Attack");
67
68 private void Awake() => animator = GetComponent<Animator>();
69
70 public void SetSpeed(float speed) => animator.SetFloat(SpeedHash, speed);
71 public void SetGrounded(bool grounded) => animator.SetBool(IsGroundedHash, grounded);
72 public void TriggerJump() => animator.SetTrigger(JumpTrigger);
73 public void TriggerAttack() => animator.SetTrigger(AttackTrigger);
74}
75```
76
77### Step 2 : Animation Events
78
79```csharp
80// Appele depuis un clip d'animation a un keyframe precis
81public void OnFootstep()
82{
83 audioService.PlaySFX(footstepClip);
84}
85
86public void OnAttackHit()
87{
88 // Activer hitbox au bon moment de l'animation
89 hitbox.SetActive(true);
90}
91
92public void OnAttackEnd()
93{
94 hitbox.SetActive(false);
95}
96```
97
98### Step 3 : StateMachineBehaviour (logique attachee aux states)
99
100```csharp
101public class AttackState : StateMachineBehaviour
102{
103 public override void OnStateEnter(
104 Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
105 {
106 animator.GetComponent<CombatSystem>().OnAttackStart();
107 }
108
109 public override void OnStateExit(
110 Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
111 {
112 animator.GetComponent<CombatSystem>().OnAttackEnd();
113 }
114}
115```
116
117### Step 4 : Animator Layers (animations partielles)
118
119```csharp
120// Controle dynamique du poids d'un layer (ex: upper body attack)
121private static readonly int UpperBodyLayer = 1;
122
123public void EnableUpperBodyOverride(float weight)
124{
125 animator.SetLayerWeight(UpperBodyLayer, weight);
126}
127```
128
129- **Layer 0** : Base (locomotion complete)
130- **Layer 1** : Upper Body Override (attaque, interaction) avec Avatar Mask
131- **Layer 2** : Additive (breathing, hit reactions)
132
133### Step 5 : Blend Trees pour la locomotion
134
135Dans l'Animator Controller :
136- Creer un Blend Tree 2D Freeform Directional
137- Parametres : `MoveX` (float), `MoveY` (float)
138- Motions : idle (0,0), walk forward (0,0.5), run forward (0,1), strafe left (-1,0), strafe right (1,0)
139
140```csharp
141private static readonly int MoveXHash = Animator.StringToHash("MoveX");
142private static readonly int MoveYHash = Animator.StringToHash("MoveY");
143
144public void SetMovement(Vector2 input)
145{
146 // Smooth damp pour eviter les changements brusques
147 animator.SetFloat(MoveXHash, input.x, 0.1f, Time.deltaTime);
148 animator.SetFloat(MoveYHash, input.y, 0.1f, Time.deltaTime);
149}
150```
151
152## Regles strictes
153
154**TOUJOURS :**
155- Cacher les hash avec `Animator.StringToHash` (pas de strings dans Update)
156- Utiliser les Animation Events pour synchroniser logique et animation (pas de timers manuels)
157- Utiliser des Animator Layers pour les animations partielles (upper body attack + lower body run)
158- Utiliser `SetFloat` avec damping pour des transitions fluides dans les blend trees
159- Detruire les `PlayableGraph` dans `OnDestroy()` pour eviter les fuites memoire
160
161**JAMAIS :**
162- `GetComponent<Animator>()` dans Update -- cacher la reference dans Awake
163- `transition duration = 0` sauf pour les state machines purement logiques (cause des snaps visuels)
164- Modifier `transform.position` manuellement quand Root Motion est actif
165- Utiliser `Play()` ou `CrossFade()` sans raison -- preferer les transitions de l'Animator Controller
166
167**PREFERER :**
168- Les Blend Trees 2D Freeform pour le mouvement directionnel
169- Les Sub-State Machines pour organiser les Animator Controllers complexes
170- Les Override Controllers pour reutiliser une state machine avec des clips differents
171- Animation Rigging plutot que `OnAnimatorIK()` pour les nouveaux projets
172
173## Skills connexes
174
175- `/unity-code-gen` -- generer des StateMachineBehaviour et boilerplate Animator
176- `/proto` -- prototyper rapidement avec des animations simples
177- `/unity-dots` -- DOTS animation pour des milliers d'entites animees
178- `/2d` -- animation 2D avec Sprite Library et Sprite Swap
179
180## Troubleshooting
181
182| Probleme | Solution |
183|----------|----------|
184| Animation ne joue pas | Verifier que le state est atteignable (transitions connectees), que le parametre est set correctement |
185| Personnage glisse/flotte | Root Motion mal configure -- verifier "Apply Root Motion" sur l'Animator et les curves du clip |
186| Blend Tree saccade | Verifier que les clips ont la meme cadence de pas (foot cycle). Ajuster le threshold |
187| IK ne fonctionne pas | Verifier que le layer a "IK Pass" active dans l'Animator Controller |
188| Animation Event pas appele | La methode doit etre publique, sur le meme GameObject que l'Animator, avec la bonne signature |
189| Transition bloquee | Verifier les conditions de transition, desactiver "Has Exit Time" si transition immediate souhaitee |
190| Layer override ne marche pas | Verifier l'Avatar Mask du layer, et que le weight > 0 |
191| PlayableGraph leak | Toujours appeler `graph.Destroy()` dans `OnDestroy()` |