Maîtriser l'environnement Unity 6 LTS, le cycle de vie MonoBehaviour, les Prefabs, ScriptableObjects, Cinemachine et l'architecture DOTS/ECS pour produire des jeux performants en C#.
Sortie en octobre 2024, Unity 6 est la version Long-Term Support (LTS) qui remplace 2022 LTS. Elle apporte le GPU Resident Drawer (rendu CPU-free), le Spatial-Temporal Post-processing (upscaling AI), le support natif WebGPU, et surtout la stabilisation complète du DOTS stack (Burst Compiler, Job System, ECS) qui était en preview depuis 2019. Côté licence : Unity Personal reste gratuit jusqu'à 200 000 USD de revenus annuels, Unity Pro est facturé 2 200 USD/siège/an. Le scandale du Runtime Fee annoncé en 2023 a été annulé par le nouveau CEO Matt Bromberg en septembre 2024.
Unity domine le marché du mobile et de l'indie : 70 % des jeux mobile installés en 2025 tournent sous Unity (Source : data.ai). Le moteur excelle pour les jeux 2D, mobile, AR/VR, casual et mid-core. À l'inverse, pour de la production AAA photoréaliste sur PC/console, Unreal 5 reste préférable (voir leçon 3). Beaucoup de studios professionnels maîtrisent les deux moteurs et choisissent selon le projet.
"Unity 6 is the most stable, performant, and AI-ready version of Unity ever." — unity.com/releases/unity-6 (octobre 2024)
L'éditeur s'organise autour de cinq fenêtres principales : Hierarchy (arborescence des GameObjects de la scène), Scene (vue 3D éditable), Game (rendu caméra runtime), Inspector (composants du GameObject sélectionné) et Project (assets sur disque). La Console affiche logs, warnings et erreurs. Une scène (.unity) est un fichier YAML décrivant un graphe de GameObjects. Un projet pro comporte typiquement plusieurs scènes additives : Persistent (managers DontDestroyOnLoad), MainMenu, Level_01, Level_02, UI_HUD.
L'arborescence d'assets standard : Assets/_Project/Scripts/, Assets/_Project/Prefabs/, Assets/_Project/Materials/, Assets/_Project/Audio/, Assets/_Project/Scenes/. Le préfixe _Project garde tes fichiers en haut du Project window. Le dossier StreamingAssets/ embarque des fichiers bruts (vidéos, fichiers JSON, ScriptableObjects exportés) accessibles via Application.streamingAssetsPath.
Tout script attaché à un GameObject hérite de MonoBehaviour. Le moteur appelle automatiquement des méthodes spéciales selon l'événement. L'ordre exact d'exécution est documenté sur docs.unity3d.com/Manual/ExecutionOrder.html et conditionne le bon fonctionnement de tout système gameplay non-trivial.
using UnityEngine;
public class PlayerController : MonoBehaviour
{
[SerializeField] private float moveSpeed = 5f;
[SerializeField] private float jumpForce = 7f;
[SerializeField] private LayerMask groundMask;
private Rigidbody rb;
private bool isGrounded;
void Awake() // appelé une fois, AVANT Start, même si l'objet est désactivé
{
rb = GetComponent<Rigidbody>();
}
void Start() // appelé une fois, après tous les Awake, avant le premier Update
{
Debug.Log("Player ready");
}
void Update() // appelé chaque frame (variable : 60-144 Hz selon FPS)
{
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
Vector3 move = new Vector3(h, 0f, v) * moveSpeed * Time.deltaTime;
transform.Translate(move, Space.World);
if (Input.GetButtonDown("Jump") && isGrounded)
rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
}
void FixedUpdate() // fixe : 50 Hz par défaut, idéal pour la physique
{
isGrounded = Physics.Raycast(transform.position, Vector3.down, 1.1f, groundMask);
}
}
Bonne pratique : récupère les composants dans Awake(), jamais dans Update() (10× plus lent). Utilise Time.deltaTime dans Update pour des mouvements frame-rate indépendants, Time.fixedDeltaTime dans FixedUpdate.
Un Prefab est un GameObject réutilisable stocké comme asset. Modifier le prefab propage les changements à toutes les instances de la scène. Les Prefab Variants (Unity 2018+) permettent d'hériter d'un prefab parent en surchargeant certaines propriétés (façon class inheritance). Les Nested Prefabs autorisent un prefab à contenir d'autres prefabs (utile pour les modulaires : un château contient des Prefab tourelles).
Les ScriptableObjects sont des assets contenant uniquement de la data (pas de Transform, pas de scène). Ils servent à découpler la configuration du code : ItemData (nom, sprite, prix), EnemyConfig (HP, dégâts, IA), QuestData. Avantage clé : un designer modifie un asset .asset dans l'Inspector sans toucher au code C#.
Cinemachine, intégré nativement depuis Unity 2019, remplace le scripting manuel de caméra par un système déclaratif : tu poses une Virtual Camera qui pointe une cible, tu choisis le Body (Tracking 3rd Person, Framing Transposer 2D, FreeLook orbital) et le Aim (Composer, Hard Look At). Pour passer d'une caméra à une autre (cinématique → gameplay), il suffit de désactiver l'une et d'activer l'autre : Cinemachine effectue un blend automatique (cubic, ease-in/out) sur la durée définie. Un Cinemachine Brain unique sur la Main Camera orchestre l'ensemble.
Le paradigme classique Unity (MonoBehaviour + GameObject) est object-oriented : chaque objet contient ses méthodes et ses data dispersés en mémoire (cache misses fréquents). Le Entity Component System (ECS) est data-oriented : les data sont stockées en arrays contigus en mémoire (chunks), processées en batch par des Systems via le Burst Compiler (compile C# en code SIMD natif) et le Job System (multithreading sans-fil-d'attente). Résultat : 10× à 100× plus rapide pour des milliers d'entités (boids, projectiles, particules).
| Critère | MonoBehaviour (OOP) | ECS (DOTS) |
|---|---|---|
| Paradigme | Object-Oriented | Data-Oriented (cache-friendly) |
| Performance max | ~1 000 GameObjects actifs | ~1 000 000 entités |
| Multithreading | Manuel, complexe | Automatique via Job System |
| Compilation | Mono / IL2CPP | Burst Compiler (SIMD natif) |
| Cas d'usage | Gameplay scripté, UI, niveaux | Boids, RTS, simulations massives |
| Courbe d'apprentissage | Facile | Raide (debugger limité) |
FindObjectOfType ou GameObject.Find dans Update : O(n) sur toute la scène, killer de perf.-= OnEvent) dans OnDestroy : sinon memory leak garanti.Le passage à Unity 6 redéfinit la frontière entre CPU et GPU grâce au GPU Resident Drawer et à la consolidation du stack DOTS. Là où l'architecture historique MonoBehaviour traitait chaque objet de la scène comme une instance C# autonome (avec son cycle de vie, son overhead managé et sa cache miss à chaque Update()), Unity 6 propose un modèle data-oriented où les composants sont stockés en mémoire contiguë par archetype dans des chunks de 16 KB. Cette organisation permet au Burst Compiler (basé sur LLVM) de générer du code SIMD natif AVX2 ou ARM NEON, multipliant les performances par 10 à 50 sur les boucles serrées de gameplay, de physique custom ou d'IA de foule. Le coût d'apprentissage est réel : il faut accepter de manipuler des IComponentData, des SystemBase, et de penser en transformations par batch plutôt qu'en méthode Update() par GameObject.
Sur le plan rendering, Unity 6 unifie enfin les deux pipelines modernes URP (Universal Render Pipeline) et HDRP (High Definition Render Pipeline) autour d'une couche commune appelée Scriptable Render Pipeline (SRP) Core. URP cible mobile, WebGL, consoles d'entrée et VR autonome (Quest 3, Vision Pro) avec un budget de 4 à 8 ms par frame. HDRP cible PC haut de gamme, PS5, Xbox Series X et offre le path tracing temps réel, le subsurface scattering, les volumetric clouds et la GI avec APV (Adaptive Probe Volumes). Le choix du pipeline est irréversible en pratique : changer URP→HDRP en cours de production casse tous les shaders, tous les matériaux et tous les VFX Graphs. Une étude de marché en amont (plateforme cible, budget GPU, équipe artistique) est donc cruciale.
Le Job System distribue les calculs sur les cœurs CPU via un thread pool managé par Unity. Un IJob classique exécute une tâche unitaire, un IJobParallelFor partitionne automatiquement un tableau de N éléments en sous-tâches confiées à autant de workers que de cœurs logiques. Le JobHandle permet d'établir des dépendances acycliques entre jobs (job B attend job A) avec un coût quasi nul. Couplé à Burst, ce système permet par exemple de simuler 100 000 ennemis IA sur une boucle de pathfinding en 1,2 ms sur un Ryzen 7 5800X, là où un MonoBehaviour classique demanderait 35 ms. Les règles d'or : pas de référence à des types managés (string, classe, GameObject) dans un job, utilisation exclusive de NativeArray<T> et NativeList<T>, structures unsafe autorisées si [BurstCompile] est appliqué, désactivation des Safety Checks en build release pour gagner 30 % supplémentaires.
Le GPU instancing tire parti d'une instruction unique de draw pour rendre des milliers d'objets identiques (matériau identique, mesh identique) en variant simplement la matrice de transformation. Unity 6 généralise ce mécanisme avec BatchRendererGroup et GPU Resident Drawer : les transforms vivent désormais en VRAM, la CPU n'a plus à pousser les données à chaque frame, et le rendu de 50 000 props (rochers, arbres, débris) tient en 2 ms GPU sur une RTX 4070. Pour exploiter pleinement ce gain il faut activer GPU instancing sur chaque matériau, utiliser des MaterialPropertyBlock pour les variations légères, et bannir les matériaux uniques par objet (un piège fréquent : modifier renderer.material à chaud crée une instance non batchable).
La Scriptable Render Pipeline (SRP) permet d'écrire son propre pipeline de rendu en C# en exploitant les RenderPass, RendererFeatures (URP) et CustomPasses (HDRP). Cas concret : ajouter un outline post-process pour un jeu cel-shaded demande 60 lignes de C# en URP via un ScriptableRendererFeature, contre 800 lignes et un fork complet du built-in pipeline historique. Les RenderGraph (intégré en Unity 6) optimisent automatiquement l'allocation des RenderTargets temporaires en analysant le graphe de passes, réduisant la bande passante mémoire de 40 % typique sur mobile.
Les Addressables remplacent l'ancien AssetBundle avec une API unifiée pour le streaming, l'over-the-air content, et le packaging multi-plateforme. Un asset référencé par AssetReference est chargé à la demande via Addressables.LoadAssetAsync<Texture2D>("hero/portrait"), le système gère le caching disque, la dépendance entre bundles, la CRC de vérification et le téléchargement CDN. Pour un MMO ou un live-ops, on déploie typiquement 2-5 GB d'assets via Addressables pour rester sous la limite store de 2 GB d'APK Android.
Le Unity Profiler moderne (Unity 6) intègre 4 modules essentiels : CPU Usage (timeline microseconde par thread), GPU Usage (timing par drawcall via API capture), Memory Profiler (snapshot des allocations managées et natives), Frame Debugger (replay frame par frame avec inspection des shader passes). Un workflow efficace consiste à profiler sur device cible (jamais sur l'Editor qui ment), à activer les Deep Profile uniquement sur les frames suspectes, et à fixer un budget par sous-système (16 ms = 8 ms gameplay + 4 ms physique + 3 ms rendu + 1 ms audio).
Un RPG doit gérer 5 000 ennemis avec un buff de régénération qui se cumule (DoT inversé). En MonoBehaviour classique, chaque ennemi fait son Update() et accumule du retard. En ECS pur, on crée un HealthRegenComponent et un système qui parcourt l'archetype en SIMD :
using Unity.Burst;
using Unity.Entities;
using Unity.Mathematics;
public struct HealthData : IComponentData { public float current; public float max; }
public struct HealthRegen : IComponentData { public float perSecond; public float duration; }
[BurstCompile]
public partial struct RegenSystem : ISystem
{
public void OnUpdate(ref SystemState state)
{
float dt = SystemAPI.Time.DeltaTime;
foreach (var (health, regen) in
SystemAPI.Query<RefRW<HealthData>, RefRW<HealthRegen>>())
{
health.ValueRW.current = math.min(health.ValueRO.max,
health.ValueRO.current + regen.ValueRO.perSecond * dt);
regen.ValueRW.duration -= dt;
}
}
}
On veut faire pousser un champ d'herbe sans tuer le framerate Quest 3. La solution : un seul mesh + un matériau GPU-instanced + un buffer de transforms.
public class GrassField : MonoBehaviour
{
public Mesh bladeMesh;
public Material grassMat;
public int count = 10000;
private Matrix4x4[] matrices;
private MaterialPropertyBlock mpb;
void Start()
{
matrices = new Matrix4x4[count];
mpb = new MaterialPropertyBlock();
for (int i = 0; i < count; i++) {
Vector3 p = new Vector3(Random.Range(-50f, 50f), 0, Random.Range(-50f, 50f));
Quaternion r = Quaternion.Euler(0, Random.Range(0, 360f), 0);
matrices[i] = Matrix4x4.TRS(p, r, Vector3.one);
}
}
void Update()
{
Graphics.DrawMeshInstanced(bladeMesh, 0, grassMat, matrices, count,
mpb, UnityEngine.Rendering.ShadowCastingMode.Off);
}
}
| Approche | Performance (10k entités) | Complexité | Cas d'usage |
|---|---|---|---|
| MonoBehaviour Update | ~28 ms CPU | ★☆☆☆☆ | Prototypage, équipe junior |
| MonoBehaviour + Object Pool | ~18 ms CPU | ★★☆☆☆ | Mobile casual, FPS classique |
| Job System (sans Burst) | ~6 ms CPU | ★★★☆☆ | IA modérée, multi-thread simple |
| Job System + Burst | ~1,3 ms CPU | ★★★★☆ | Simulation physique custom |
| ECS + Burst + Jobs | ~0,8 ms CPU | ★★★★★ | RTS, foule, MMO, projectiles massifs |
| GPU Compute (HLSL) | ~0,2 ms GPU | ★★★★★ | Particules, fluides, foule purement visuelle |
| GPU Resident Drawer | ~50k props @ 2 ms | ★★★☆☆ | Vegetation, débris, open world |
foreach sur List<T> en hot path : préférer for (int i = 0; i < list.Count; i++) ou passer en NativeArray.MaterialPropertyBlock et un matériau partagé.Scene.UnloadAsync ne libère pas les Addressables instanciés, il faut Addressables.ReleaseInstance(go) explicitement.Resources.Load en cours de gameplay : pré-charger tout avec Addressables au démarrage de niveau.CinemachineFreeLook ne lit pas l'Input System par défaut, il faut activer Cinemachine.Input Provider sinon la caméra reste figée."Burst compiles a subset of C# to highly optimized native code using the LLVM compiler framework. Burst is particularly suited for code where you need to do a lot of math (Mathematics, Physics) on a lot of data (Collections, ECS)." — docs.unity3d.com — Burst manual
"DOTS (Data-Oriented Technology Stack) is a combination of technologies and packages that delivers a data-oriented approach to writing code. Together, these technologies offer better performance and improved iteration times." — unity.com/dots
| Terme | Définition |
|---|---|
| Draw call | Commande envoyée à l'API graphique (Vulkan, Metal, DX12) pour dessiner un mesh — coût CPU + setup GPU non négligeable. |
| Batching | Regroupement de plusieurs meshes partageant le même matériau en un seul draw call (static, dynamic, SRP batcher, GPU instancing). |
| LOD (Level of Detail) | Mesh simplifié activé en fonction de la distance caméra — économise polygones et bande passante GPU. |
| Occlusion culling | Élimination par le moteur des objets cachés par d'autres (PVS pré-calculé ou GPU-driven occlusion). |
| PBR (Physically Based Rendering) | Modèle de matériau basé sur albédo, métallique, roughness, normal, AO — standard depuis 2014. |
| Normal map | Texture encodant les normales d'une surface — simule des détails géométriques sans ajouter de polygones. |
| Lightmap | Texture pré-calculée stockant l'éclairage statique d'une scène — économise les calculs runtime. |
| MRT (Multiple Render Targets) | Écriture simultanée de plusieurs textures par un shader (G-Buffer du deferred shading). |
| Forward vs Deferred | Forward = un shader par objet (rapide, peu de lumières) ; Deferred = G-buffer + lighting pass (scalable à 100+ lumières). |
| Archetype (ECS) | Combinaison unique de composants définissant un layout mémoire — stockage par chunk de 16 KB. |
La leçon suivante est également gratuite. Découvrez-la sans inscription.
Leçon 2 — Continuer →Choisis quels cookies tu acceptes — modifiable à tout moment.