Construire un jeu complet avec physique réaliste, animations fluides, son immersif, UI moderne et multijoueur en réseau via Unity Netcode for GameObjects.
Le moteur physique d'Unity repose sur PhysX (NVIDIA) pour la 3D et Box2D pour la 2D. Un objet acquiert un comportement physique en ajoutant un Rigidbody (3D) ou Rigidbody2D ; sa forme de collision est définie par un Collider (Box, Sphere, Capsule, Mesh). Les paramètres clés : mass (kg), drag (résistance air linéaire), angular drag (rotation), useGravity, isKinematic (ignore les forces, pilotable par script).
Les Layers (32 max) permettent de filtrer ce qui collide avec quoi (matrice Physics > Layer Collision Matrix). Exemple : la layer Player ignore Pickup mais collide avec Wall. Les Raycasts projettent un rayon depuis un point dans une direction et retournent le premier hit : indispensable pour le tir, la détection de sol, la sélection à la souris.
using System.Collections;
using UnityEngine;
public class WeaponShooter : MonoBehaviour
{
[SerializeField] private float fireRate = 0.2f;
[SerializeField] private float range = 100f;
[SerializeField] private int damage = 25;
[SerializeField] private LayerMask hitMask;
[SerializeField] private ParticleSystem muzzleFlash;
private bool canFire = true;
void Update()
{
if (Input.GetButton("Fire1") && canFire)
StartCoroutine(FireBullet());
}
IEnumerator FireBullet()
{
canFire = false;
muzzleFlash.Play();
if (Physics.Raycast(transform.position, transform.forward, out RaycastHit hit, range, hitMask))
{
Debug.DrawLine(transform.position, hit.point, Color.red, 1f);
var enemy = hit.collider.GetComponent<Enemy>();
if (enemy != null) enemy.TakeDamage(damage);
}
yield return new WaitForSeconds(fireRate);
canFire = true;
}
}
Coroutine : fonction qui peut suspendre son exécution via yield return. Idéale pour timer, animation, séquence d'actions sans bloquer le thread principal.
Le composant Animator exécute un Animator Controller (.controller), c'est-à-dire une state machine visuelle où chaque état est un clip d'animation (Idle, Walk, Run, Jump, Death). Les transitions entre états sont conditionnées par des paramètres typés (Float, Int, Bool, Trigger). Exemple : transition Idle→Walk si Speed > 0.1. Les Sub-State Machines regroupent plusieurs états (ex : Combat = Attack1+Attack2+Block).
Le Blend Tree mélange plusieurs clips selon un ou deux paramètres : un Blend Tree 2D (X = speed, Y = direction) permet à un personnage de marcher dans 8 directions à partir de 8 clips, avec interpolation fluide. C'est la base de l'animation moderne 3D.
public class CharacterAnimator : MonoBehaviour
{
private Animator anim;
private static readonly int Speed = Animator.StringToHash("Speed");
private static readonly int JumpTrigger = Animator.StringToHash("Jump");
void Awake() { anim = GetComponent<Animator>(); }
public void UpdateMovement(float speed) {
anim.SetFloat(Speed, speed, 0.1f, Time.deltaTime); // damping 0.1s
}
public void TriggerJump() { anim.SetTrigger(JumpTrigger); }
}
Note perf : Animator.StringToHash convertit une string en int au démarrage. Toujours utiliser le hash dans Update (10× plus rapide que la string).
La Timeline (Window > Sequencing > Timeline) permet de séquencer cinématiques : pistes Animation, Audio, Activation (GameObject on/off), Control (Sub-Timeline) et Signals (events). Idéale pour cutscenes et tutoriels interactifs. L'Inverse Kinematics (IK) calcule la position des os intermédiaires (coude, genou) à partir d'une cible (main, pied). Activé via Animator > IK Pass et le hook OnAnimatorIK(). Le package Animation Rigging ajoute des constraints visuels (Two Bone IK, Multi-Aim, Chain IK) pour ajuster une animation à un objet du monde (poser la main sur une poignée, viser un ennemi).
Un AudioSource attaché à un GameObject lit un AudioClip en 2D (UI, musique) ou 3D (positionnel, atténuation distance). L'AudioMixer permet de router les sources dans des groupes (Music, SFX, Voice) avec effets DSP (lowpass, reverb, compressor) et de gérer le volume global via Snapshots (Combat = ducking music, Menu = music up). En production AAA, FMOD Studio et Audiokinetic Wwise remplacent l'audio Unity natif : workflow audio designer dédié, events paramétriques, occlusion temps réel, profilage mémoire. FMOD intégration via le package gratuit fmod.com/unity.
uGUI (Unity GUI, depuis 2014) est l'ancien système : composants Canvas, Image, Text, Button posés dans la scène. Simple mais coûteux (drawcalls élevés, layout en CPU). UI Toolkit (depuis Unity 2021, stable Unity 6) est le successeur inspiré du web : description en UXML (HTML-like) + style en USS (CSS-like) + binding C#. Avantages : 10× plus performant, hot-reload des styles, layout flexbox. UI Toolkit est désormais recommandé pour toute nouvelle UI runtime.
| Critère | uGUI (legacy) | UI Toolkit (Unity 6) |
|---|---|---|
| Description | Scène + GameObjects | UXML + USS + C# |
| Performance | Moyenne (drawcalls) | Élevée (batched) |
| Layout | Anchors + Layout Group | Flexbox CSS |
| Hot-reload | Non | Oui (USS) |
| Recommandé pour | Projets legacy | Tous nouveaux projets |
Unity Netcode for GameObjects (NGO, ex-MLAPI) est le framework officiel multijoueur depuis 2021. Architecture client-host ou dedicated server avec NetworkObject (spawn synchronisé), NetworkVariable<T> (variables auto-synchronisées) et RPC (ServerRpc, ClientRpc). Le service Unity Relay (Unity Gaming Services, freemium) permet le NAT punch-through gratuit pour 100 CCU. Unity Lobby gère matchmaking, codes de room, données joueurs. Pour des jeux compétitifs (FPS, MOBA), préférer une architecture dedicated server sur Unity Multiplay Hosting ou Edgegap.
"Netcode for GameObjects is built to be extensible and to scale. It works for casual co-op and competitive shooters alike." — docs.unity3d.com/Packages/com.unity.netcode.gameobjects
Rigidbody.AddForce dans Update : toujours dans FixedUpdate (sinon comportement physique aléatoire).La couche physique et la couche animation d'Unity sont deux sous-systèmes coûteux qui partagent une caractéristique fondamentale : elles tournent à fréquence fixe (FixedUpdate à 50 Hz par défaut pour la physique, Animator évalué à chaque frame de rendu) et leur découplage avec le Update gameplay est source des bugs les plus subtils en production. Comprendre quand un événement se produit dans le pipeline est aussi important que comprendre quoi il produit. Le Script Execution Order (Edit → Project Settings → Script Execution Order) permet de prioriser un script critique (par exemple un Camera Follow doit s'exécuter en LateUpdate après le mouvement physique du joueur, sinon la caméra tremble d'une frame).
Côté netcode, Unity propose désormais deux solutions officielles : Netcode for GameObjects (NGO) pour les projets clé en main avec composants NetworkBehaviour, et Netcode for Entities pour les projets DOTS où la performance prime. Une troisième voie communautaire, Mirror, reste populaire pour les projets indé : fork de l'ancien UNet, compatible Unity 6, communauté active de 12 000 développeurs sur Discord. Le choix dépend du modèle topologique : authoritative server (FPS compétitif, MMO), client-host listen server (coop 2-8 joueurs), ou peer-to-peer (jeu de stratégie tour par tour). Aucun moteur ne résout magiquement la latence : la conception du gameplay (input delay caché, animation de feedback, sound buffer) reste responsabilité du designer.
Le package Animation Rigging apporte à Unity ce que MotionBuilder offre depuis 2003 : la possibilité de superposer des contraintes IK (Inverse Kinematics) sur une animation existante. Concrètement, un personnage qui tient une arme verra sa main gauche s'aligner dynamiquement sur la poignée de l'arme même si l'animation source a été faite pour une autre arme — un seul TwoBoneIKConstraint entre épaule-coude-poignet, target sur le grip de l'arme, et le runtime résout en temps réel. Les contraintes disponibles sont nombreuses : Damped Transform (suivi avec amortissement), Multi-Aim (la tête regarde une cible), Multi-Parent (swap d'objet attaché), Override Transform (force une position). Ce système est utilisé en production AAA chez Naughty Dog et Insomniac pour superposer des animations procédurales sur des clips capturés en mocap.
Le NavMesh reste la solution standard pour le pathfinding. Le NavMesh Surface permet désormais de générer la navmesh à runtime (dynamique pour les niveaux procéduraux), et les NavMesh Modifiers permettent d'exclure ou de réétiqueter des zones (escaliers, eau, falaises). Un NavMesh Agent avec updatePosition = false et updateRotation = false permet de récupérer juste le path calculé pour appliquer son propre déplacement (cinematic precision, root motion). Pour les jeux RTS où l'on déplace 200 unités, basculer sur A* Pathfinding Project Pro (asset store, 100 USD) reste plus performant car il offre du flowfield et du multi-thread, là où NavMesh est limité à 1 thread.
Le composant Cloth (PhysX cloth) simule un tissu via un mailmesh de particules connectées par springs. Coût CPU : 0,3 à 1,2 ms par cape sur PC, prohibitif sur mobile. Pour un personnage avec cape, robe et cheveux flottants, on dépasse vite les 4 ms : la production AAA préfère désormais les bone chains avec contraintes Dynamic Bone (asset store) ou Magica Cloth 2 (75 USD) qui tournent en jobs multi-thread Burst-compiled.
Mirror vs Netcode for GameObjects (NGO) : Mirror offre une API plus mature et une licence MIT permissive, NGO est officiellement supportée par Unity avec roadmap publique. Sur 5 000 objets répliqués, Mirror tient 60 FPS avec snapshot interpolation, NGO tombe à 35 FPS sans optimisations manuelles (subnet de pertinence, batch size, custom serializer). Pour un jeu coop 4 joueurs, NGO suffit largement. Pour un MMO 100+ joueurs, considérer Photon Fusion 2 (rollback netcode, prediction) ou Unity Multiplayer Services + Game Server Hosting.
La lag compensation consiste à rejouer côté serveur l'état du monde au moment où le client a tiré (typiquement RTT/2 = 50 ms en arrière). C'est ce qui permet à un joueur à 100 ms de ping de toucher une cible avec un hitscan. L'implémentation nécessite de garder un historique circulaire des hitboxes (10-20 frames) côté serveur. Le piège classique : un joueur peut se tuer derrière un mur car son écran montre l'ennemi à découvert (déjà rentré en couverture côté serveur) — c'est le fameux "shot around corner" qui rage les joueurs CS et Valorant.
Un FPS coop veut empêcher le cheat tout en restant snappy. Le client envoie l'input, le serveur rejoue la hitbox cible à serverTick - clientRTT/2.
using Unity.Netcode;
using UnityEngine;
public class WeaponServer : NetworkBehaviour
{
[ServerRpc]
public void FireServerRpc(Vector3 origin, Vector3 dir, float clientTick)
{
// Re-simulate hitbox states at the client's perceived time
float lagMs = (NetworkManager.ServerTime.Time - clientTick) * 1000f;
var snapshot = HitboxHistory.GetClosest(clientTick);
snapshot.Apply(); // teleport hitboxes in past pose
if (Physics.Raycast(origin, dir, out var hit, 200f, LayerMask.GetMask("Hitbox")))
{
var target = hit.collider.GetComponentInParent<HealthSync>();
target?.TakeDamageServer(25);
}
snapshot.Restore(); // teleport back to present
}
}
Un personnage monte un escalier dont la hauteur de marche varie. L'animation walk_cycle est plate, mais on veut que les pieds touchent réellement chaque marche.
using UnityEngine;
using UnityEngine.Animations.Rigging;
[RequireComponent(typeof(Animator))]
public class FootIKAdjust : MonoBehaviour
{
public TwoBoneIKConstraint leftFootIK;
public TwoBoneIKConstraint rightFootIK;
public LayerMask groundMask;
public float rayHeight = 1.5f;
void OnAnimatorIK()
{
AdjustFoot(leftFootIK, HumanBodyBones.LeftFoot);
AdjustFoot(rightFootIK, HumanBodyBones.RightFoot);
}
void AdjustFoot(TwoBoneIKConstraint ik, HumanBodyBones bone)
{
Animator anim = GetComponent<Animator>();
Vector3 footPos = anim.GetBoneTransform(bone).position;
if (Physics.Raycast(footPos + Vector3.up * rayHeight, Vector3.down,
out var hit, rayHeight + 0.5f, groundMask))
{
ik.data.target.position = hit.point + Vector3.up * 0.07f;
ik.weight = 1f;
}
else ik.weight = 0f;
}
}
| Approche netcode | Latence ressentie | Anti-cheat | Cas d'usage |
|---|---|---|---|
| Peer-to-peer relay | Faible si proche | ★☆☆☆☆ | Coop 2 joueurs, jeu de table |
| Listen server (client-host) | 0 ms hôte, RTT clients | ★★☆☆☆ | Coop 4-8, hôte = ami |
| Dedicated server | RTT uniform | ★★★★☆ | FPS compétitif, MMO |
| NGO snapshot interp | ~100 ms perçu | ★★★☆☆ | Coop, MMO casual |
| Photon Fusion rollback | ~16 ms perçu | ★★★★☆ | Fighting, FPS rapide |
| Mirror authoritative | ~80 ms perçu | ★★★☆☆ | Indé MMO, RTS |
| WebRTC data channel | RTT brut | ★☆☆☆☆ | Web HTML5, navigateur |
Rigidbody.MovePosition suivi d'un Raycast dans la même frame peut retourner l'ancienne position — appeler Physics.SyncTransforms() explicitement.updatePosition = true et qu'une animation root motion est active, conflit garanti — désactiver l'un des deux.Time.timeScale = 0 puis reprise : appeler cloth.ClearTransformMotion() avant reprise."Netcode for GameObjects is a high-level networking library built for Unity for you to abstract networking logic. It enables you to send GameObjects and world data across a networking session to many players at once." — docs-multiplayer.unity3d.com
"Animation Rigging lets you create and organize sets of constraints based on C# Animation Jobs to address different requirements related to animation rigging." — docs.unity3d.com — Animation Rigging
| Terme | Définition |
|---|---|
| FixedUpdate | Méthode appelée à fréquence fixe (50 Hz par défaut) pour les calculs physiques déterministes. |
| Root motion | Déplacement du personnage piloté par l'animation elle-même (et non par le script). |
| IK (Inverse Kinematics) | Calcul des rotations d'os pour atteindre une position cible (target). |
| NavMesh | Maillage de navigation pré-calculé pour le pathfinding A*. |
| Snapshot interpolation | Technique réseau qui interpole entre 2 états reçus du serveur pour lisser le mouvement. |
| Client prediction | Le client simule localement le résultat de son input avant la confirmation serveur. |
| Server reconciliation | Quand le serveur diverge du client, on rejoue les inputs depuis le dernier état confirmé. |
| RTT (Round Trip Time) | Temps aller-retour client-serveur ; latence ressentie = RTT/2 + buffer. |
| Tick rate | Fréquence à laquelle le serveur simule le monde (20-128 Hz selon le jeu). |
| Snapshot delta | Envoi par le serveur uniquement des champs modifiés depuis le snapshot précédent (économie bande passante). |
Inscrivez-vous pour accéder aux 5 autres leçons + le quiz final.
Créer mon compteChoisis quels cookies tu acceptes — modifiable à tout moment.