Du niveau débutant à pro : installation, C#, architecture, IA, optimisations, build & publication.
Unity est un moteur de jeu multiplateforme (2D/3D/VR/AR) très populaire. Ce guide couvre :
✔ Installation & interface
✔ Bases C# et scripting Unity
✔ Collisions, physique, UI, animations
✔ Architecture pro, patterns, ScriptableObjects
✔ Addressables, optimisation & profiling
✔ IA (FSM, NavMesh), multi‑scènes, sauvegarde
✔ Builds (PC/Mobile/WebGL) & publication
✔ Outils pro : Git, CI/CD, tests
✔ Bonus : Mini‑jeu clé‑en‑main + prompts Copilot Chat (VS Code)
Niveau requis : débutant motivé → intermédiaire/pro en fin de guide.
Téléchargez Unity Hub
Installez une version LTS (stabilité)
Modules conseillés : Android Build Support, iOS (macOS), Windows/Mac/Linux, WebGL, Visual Studio/VS Code Integration
Créez un projet : 2D (URP 2D) ou 3D (URP/HDRP selon besoins)
Astuce : une version LTS par projet évite les incompatibilités.
Fenêtres clés :
• Hierarchy : objets de la scène
• Scene View : édition du monde
• Game View : rendu caméra
• Inspector : propriétés des composants
• Project : assets (scripts, art, audio)
• Console : logs, erreurs
Raccourcis : ALT (orbiter), F (focus), W/E/R (move/rotate/scale), CTRL+D (dupliquer).
Code:
using UnityEngine;
public class Exemple : MonoBehaviour { void Start() { Debug.Log("Départ !"); } void Update() { /* 1x par frame / } void FixedUpdate() { / Physique (timestep fixe) / } void OnCollisionEnter(Collision col) { / Collision 3D / } void OnTriggerEnter(Collider other) { / Trigger 3D */ } }
Concepts : GameObject, Composants, Transform, Prefab, Tag/Layer, Rigidbody, Collider, Materials.
3D — Transform.Translate()
Code:
public class PlayerController3D : MonoBehaviour { public float speed = 5f; void Update() { float x = Input.GetAxis("Horizontal"); float z = Input.GetAxis("Vertical"); Vector3 dir = new Vector3(x, 0, z); transform.Translate(dir * speed * Time.deltaTime, Space.World); } }
2D — Rigidbody2D
Code:
using UnityEngine;
[RequireComponent(typeof(Rigidbody2D))] public class PlayerController2D : MonoBehaviour { public float speed = 6f; Rigidbody2D rb; void Awake() { rb = GetComponent(); } void FixedUpdate() { Vector2 input = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical")); rb.velocity = input.normalized * speed; } }
• Ajouter un Collider + Rigidbody (3D) ou Rigidbody2D (2D).
• Différence Collision (solide) vs Trigger (détecteur).
Code:
// 3D void OnTriggerEnter(Collider other) { if (other.CompareTag("Pickup")) { /* ramasser */ } }
• Renderer.material.color = Color.red; pour tester rapidement
• Utilisez URP pour de meilleures perfs mobiles
• Post‑Processing : Bloom, Vignette (avec modération)
Code:
using UnityEngine.UI;
public class UIHud : MonoBehaviour { public Text scoreText; int score; public void AddScore(int v) { score += v; scoreText.text = "Score: " + score; } }
Astuce : utilisez des Layout Groups & Anchors pour l’adaptativité d’écran.
Scène :
• Player (Sprite + Rigidbody2D + Collider2D, Tag=Player)
• 10 Pickups (Trigger)
• 2 Enemies (IA simple patrouille)
• Canvas → Text Score
Scripts :
GameManager.cs
Code:
using UnityEngine; using UnityEngine.UI;
public class GameManager : MonoBehaviour { public static GameManager I; public Text scoreText; int score;
void Awake() { I = this; UpdateUI(); }
public void AddScore(int v) { score += v; UpdateUI(); }
void UpdateUI() { scoreText.text = "Score: " + score; }
}
Collectible.cs
Code:
using UnityEngine;
public class Collectible : MonoBehaviour { void OnTriggerEnter2D(Collider2D other) { if (other.CompareTag("Player")) { GameManager.I.AddScore(1); Destroy(gameObject); } } }
EnemyPatrol.cs
Code:
using UnityEngine;
public class EnemyPatrol : MonoBehaviour { public Transform[] points; public float speed = 3f; int index;
void Update()
{
if (points.Length == 0) return;
Transform target = points[index];
transform.position = Vector3.MoveTowards(transform.position, target.position, speed * Time.deltaTime);
if (Vector3.Distance(transform.position, target.position) < 0.05f)
index = (index + 1) % points.Length;
}
}
Objectifs : ramassez 10 objets sans toucher les ennemis.
• Player (CharacterController)
• Obstacles qui défilent (Object Pool)
• Score + vitesse croissante
PlayerRunner.cs
Code:
using UnityEngine;
[RequireComponent(typeof(CharacterController))] public class PlayerRunner : MonoBehaviour { CharacterController cc; public float forwardSpeed = 8f, laneWidth = 2f, laneChangeSpeed = 10f; int lane; // -1, 0, 1
void Awake(){ cc = GetComponent<CharacterController>(); }
void Update()
{
if (Input.GetKeyDown(KeyCode.LeftArrow)) lane = Mathf.Clamp(lane - 1, -1, 1);
if (Input.GetKeyDown(KeyCode.RightArrow)) lane = Mathf.Clamp(lane + 1, -1, 1);
Vector3 pos = transform.position;
float targetX = lane * laneWidth;
pos.x = Mathf.Lerp(pos.x, targetX, laneChangeSpeed * Time.deltaTime);
transform.position = pos;
cc.Move(Vector3.forward * forwardSpeed * Time.deltaTime);
}
}
ObstaclePool.cs
Code:
using UnityEngine; using System.Collections.Generic;
public class ObstaclePool : MonoBehaviour { public GameObject prefab; public int size = 12; public float spacing = 10f; Queue q = new Queue(); Transform player;
void Start()
{
player = GameObject.FindGameObjectWithTag("Player").transform;
for (int i=0;i<size;i++)
{
var go = Instantiate(prefab);
go.SetActive(false);
q.Enqueue(go);
}
for (int i=0;i<size;i++) Spawn(i * spacing + 20f);
}
void Update()
{
foreach (var go in q)
{
if (go.activeSelf && go.transform.position.z < player.position.z - 10f)
{
go.SetActive(false);
Spawn(player.position.z + spacing * size);
}
}
}
void Spawn(float z)
{
var go = q.Dequeue();
go.transform.position = new Vector3(Random.Range(-1,2)*2f, 0, z);
go.SetActive(true);
q.Enqueue(go);
}
}
Code:
/Assets /Scripts /Core // Extensions, utils, events /Managers // Game, Audio, Save, UI /Gameplay // Player, Enemies, Items /Data // ScriptableObjects /UI // View + Presenter /Prefabs /Scenes // Boot, MainMenu, Level01, UI /Art // Models, Textures, Animations /Audio
Bonnes pratiques : SRP, Namespaces, Prefabs partout, objets “Boot” + “DontDestroyOnLoad”.
Singleton (sobre)
Code:
public class AudioManager : MonoBehaviour { public static AudioManager I { get; private set; } void Awake(){ if (I!=null && I!=this){ Destroy(gameObject); return; } I=this; DontDestroyOnLoad(gameObject); } }
Event/Observer
Code:
using System;
public static class GameEvents { public static Action OnGameOver; public static void RaiseGameOver() => OnGameOver?.Invoke(); }
Object Pooling (voir runner) — réduit allocations/GC.
Code:
[CreateAssetMenu(menuName="Data/EnemyStats")] public class EnemyStats : ScriptableObject { public string id; public int hp; public float speed; public int scoreValue; }
Stockez les tables d’objets/ennemis/armes en SO, pas en code dur.
Code:
using UnityEngine.SceneManagement; // Depuis une scène Boot SceneManager.LoadScene("UI", LoadSceneMode.Additive); SceneManager.LoadScene("Level01", LoadSceneMode.Additive);
Avantages : UI séparée, streaming de zones, chargements rapides.
FSM simple
Code:
public enum EnemyState { Idle, Patrol, Chase, Attack }
NavMeshAgent
Code:
using UnityEngine; using UnityEngine.AI;
[RequireComponent(typeof(NavMeshAgent))] public class EnemyChase : MonoBehaviour { public Transform target; NavMeshAgent agent; void Awake(){ agent = GetComponent(); } void Update(){ if (target) agent.SetDestination(target.position); } }
Code:
[System.Serializable] public class SaveData { public int highScore; public float volume; }
public static class SaveSystem { static string Path => Application.persistentDataPath + "/save.json";
public static void Save(SaveData data)
{
var json = JsonUtility.ToJson(data);
System.IO.File.WriteAllText(Path, json);
}
public static SaveData Load()
{
if (System.IO.File.Exists(Path))
return JsonUtility.FromJson<SaveData>(System.IO.File.ReadAllText(Path));
return new SaveData();
}
}
Code:
// Exemple d'appel (après installation du package Addressables) using UnityEngine.AddressableAssets; using UnityEngine.ResourceManagement.AsyncOperations;
public class Loader : MonoBehaviour { public string key = "enemy01"; void Start() { Addressables.LoadAssetAsync(key).Completed += OnLoaded; } void OnLoaded(AsyncOperationHandle h) { if (h.Status == AsyncOperationStatus.Succeeded) Instantiate(h.Result); } }
• Batching : cochez “Static” pour le décor, limitez les matériaux.
• LOD Groups pour modèles haute/longue distance.
• Physics : réduisez les couches d’interaction (Project Settings → Physics).
• GC : évitez les allocations en Update(), utilisez caches/réutilisation.
• Profiler : analyse CPU/GPU/Mémoire/Rendering.
• Build Report : taille par asset/assembly.
• Unity Test Framework (NUnit)
• Logs ciblés : Debug.LogWarning/Error, Assertions
• Gizmos pour visualiser zones/IA en Scene View
Code:
using NUnit.Framework; public class MathTests { [Test] public void Clamp_Works(){ Assert.AreEqual(5, Mathf.Clamp(6,0,5)); } }
• Git LFS pour les assets binaires (textures, son)
• Stratégie branches : main (stable), develop, feature/*
• CI : build automatique (GitHub Actions / Azure Pipelines) pour PC/WebGL/Android
• Convention nommage, code style (EditorConfig), PR avec revues
• Localization Package pour textes/Assets
• Input System (nouveau) → Actions, Device‑agnostic, Rebinding UI
Étapes : File → Build Settings → Platform → Add Open Scenes → Build
• PC (EXE/APP)
• Android (APK/AAB) : SDK/NDK via Hub, Mode Dev, ADB install
• WebGL : hébergeable sur itch.io, site perso
• iOS : nécessite Xcode (macOS)
Astuce : maintenez un “Build Profile” par plateforme (qualité, résolution, backend).
Tâche courte (ticket) → branche feature
Implémentation + tests rapides
Profilage (si gameplay sensible)
Commit petit & clair, PR → review
Merge develop → main via release, tag version
Build CI → validation QA
Installer : VS Code + C# Dev Kit + Unity extensions. Ouvrir le projet (dossier /Assets).
Prompts prêts à l’emploi :
• “Génère un script C# Unity pour un Object Pool générique réutilisable, sans allocations en Update, avec Reset().”
• “Explique pourquoi mon OnTriggerEnter2D ne se déclenche pas et liste les vérifications à faire.”
• “Refactorise ce PlayerController pour séparer Input/Move/Jump en méthodes testables, en évitant GetComponent en Update.”
• “Ajoute des commentaires XMLdoc et conversions en ScriptableObjects pour ces constantes.”
• “Crée des tests EditMode pour EnemySpawner afin de vérifier le rythme d’apparition.”
Exemple question/réponse (dans un fichier ouvert) :
Q: “Optimise cette méthode Update pour réduire le GC et éviter les recherches coûteuses.”
R: “Mets en cache les références dans Awake(), remplace new Vector3 chaque frame par un champ réutilisé, passe Input System, etc.”
Collectibles 2D : Ajoute un compteur de temps, un meilleur score persistant (JSON).
→ Critères : timer UI, sauvegarde highScore, bouton Rejouer.
Runner 3D : Ajoute une augmentation progressive de vitesse + Lanes animées + son.
→ Critères : difficulté croissante, audio mixé (AudioMixer), pas de drop FPS.
Addressables : Charge un skin de personnage par clé depuis un menu.
→ Critères : chargement async, placeholder si échec, logs propres.
IA NavMesh : Ajoute zones patrouille + poursuite + attaque.
→ Critères : transitions FSM claires, raycasts pour ligne de vue.
Avant un build :
• Pas d’erreurs Console
• Quality Settings adaptés plateforme
• Textures compressées, Meshes optimisés
• Addressables buildés (si utilisés)
• Scènes listées dans Build Settings
Avant publication :
• Résolution UI (toutes tailles d’écran)
• Économie batterie (mobile)
• Permissions (Android/iOS)
• Crash‑free rate (tests réels)
• Page Itch/Steam claire (captures, trailer court)
Avec ce guide, vous pouvez :
✔ Construire un prototype 2D/3D
✔ Structurer un projet pro (patterns, SO, multi‑scènes)
✔ Optimiser, profiler, packager avec Addressables
✔ Sauvegarder, tester, itérer et publier
✔ Booster votre productivité avec Copilot Chat (VS Code)
Besoin d’une version PDF prête à imprimer, d’un modèle de projet “starter”, ou d’un mini‑jeu guidé étape par étape ? Dis‑le et je te le génère.
Annexe — Snippets utiles
Extension : GetOrAddComponent
Code:
public static class ComponentExt { public static T GetOrAdd(this GameObject go) where T: Component { var c = go.GetComponent(); return c ? c : go.AddComponent(); } }
Timer simple
Code:
public class SimpleTimer { float start; public void Start(){ start = Time.time; } public float Elapsed => Time.time - start; }
Gizmos de debug
Code:
void OnDrawGizmosSelected() { Gizmos.color = Color.yellow; Gizmos.DrawWireSphere(transform.position, 3f); }