Objectif : transformer le design en contraintes techniques minimales
Cette section du GDD fixe les spécifications techniques minimales nécessaires pour implémenter le jeu de façon cohérente et testable. Elle sert de pont entre les intentions de design et la réalité de production : quels systèmes doivent exister, quelles données ils consomment, quels événements ils émettent, et quelles valeurs doivent être configurables pour faciliter l’équilibrage sans modifier le code.
Principes à respecter
- Déterminisme fonctionnel : à entrée identique, le résultat doit être reproductible (utile pour debug et tests).
- Données séparées du code : les paramètres de gameplay (vitesses, dégâts, timers, etc.) vivent dans un fichier/asset de données.
- Contrats clairs : chaque système expose des champs et événements attendus (contrat de données).
- Minimum viable : on spécifie le nécessaire (pas d’architecture “parfaite”), mais on évite les impasses (ex. sauvegarde extensible).
Système de scènes (niveaux, menus, transitions)
Contraintes techniques
- Le jeu est découpé en scènes :
MainMenu,Options,Level_X,GameOver,Victory(ou équivalents). - Un SceneManager central gère : chargement, déchargement, transitions, et passage de paramètres (ex. identifiant de niveau, point d’apparition).
- Les transitions doivent être non bloquantes (écran de chargement simple ou fondu) si le moteur le nécessite.
Règles d’implémentation
- Définir une liste de scènes et leurs rôles (menu, gameplay, fin).
- Définir un identifiant unique par niveau :
levelId. - Définir un point d’entrée standard pour un niveau :
SpawnPointId(par défautstart). - Définir les transitions autorisées (ex. menu → niveau, niveau → game over, niveau → victoire).
Événements clés (scènes)
OnSceneLoadStart(sceneId)OnSceneLoaded(sceneId)OnSceneUnloadStart(sceneId)OnSceneUnloaded(sceneId)
Gestion des entrées (input) : actions, mapping, priorités
Concept
On ne code pas “touche X” dans la logique gameplay. On code des actions (Sauter, Attaquer, Pause) et on mappe ces actions à des entrées (clavier/manette). Cela rend le jeu configurable et testable.
Contraintes techniques
- Un InputManager expose des actions :
Move(axe),Jump,Attack,Interact,Pause. - Gestion de contexte : gameplay vs UI (quand un menu est ouvert, les actions gameplay sont ignorées).
- Optionnel minimal : remappage (si prévu), sinon mapping fixe documenté.
Étapes pratiques
- Écrire la liste des actions (nom stable) et leur type : bouton, axe, maintien.
- Définir les règles de répétition : ex.
Jumpdéclenché sur “press”, pas sur “hold”. - Définir la priorité : UI > Pause > Gameplay.
- Documenter les valeurs normalisées :
Move.x∈ [-1, 1].
| Action | Type | Contexte | Notes |
|---|---|---|---|
Move | Axe | Gameplay | Normalisé, lissage optionnel |
Jump | Bouton | Gameplay | Déclenchement sur appui |
Attack | Bouton | Gameplay | Cooldown géré côté gameplay |
Pause | Bouton | Global | Ouvre/ferme menu pause |
Sauvegarde simple : progression et options
Concept
La sauvegarde minimale couvre : (1) la progression (niveau débloqué, checkpoints) et (2) les options (volume, sensibilité, affichage). Elle doit être robuste aux mises à jour (versionnement).
Contraintes techniques
- Un SaveManager sérialise un objet de données (JSON/binaire selon moteur) dans un emplacement persistant.
- Le fichier de sauvegarde contient un champ
saveVersionpour migration simple. - La sauvegarde est déclenchée sur événements : checkpoint atteint, fin de niveau, changement d’options.
Étapes pratiques
- Définir le schéma de données (voir “Contrat de données”).
- Implémenter
Load()au lancement (menu) etApplyOptions(). - Implémenter
SaveProgress()surOnCheckpointReachedetOnLevelCompleted. - Prévoir une valeur par défaut si aucune sauvegarde n’existe.
Événements clés (sauvegarde)
OnOptionsChanged(options)→ sauvegarde immédiateOnCheckpointReached(levelId, checkpointId)→ sauvegarde progressionOnLevelCompleted(levelId)→ sauvegarde progression + déblocage
Gestion des collisions : couches, règles et réponses
Concept
Les collisions doivent être prévisibles : on définit des couches (player, enemy, world, projectile, pickup) et des règles d’interaction. La réponse à collision (bloquer, déclencher, ignorer) est spécifiée dans le GDD pour éviter les incohérences.
Contraintes techniques
- Définir une matrice de collision (qui collide avec qui).
- Différencier collision physique (sol/murs) et trigger (zones de dégâts, pickups, checkpoints).
- Les dégâts ne sont pas “dans la collision” : la collision déclenche un événement, le système de combat applique les règles (invincibilité, knockback, etc.).
Matrice minimale (exemple)
| De \ Vers | World | Player | Enemy | Projectile | Pickup |
|---|---|---|---|---|---|
| Player | Bloque | — | Trigger (dégâts) | Trigger (dégâts) | Trigger (ramasser) |
| Enemy | Bloque | Trigger (dégâts) | Bloque/Ignore | Trigger (dégâts) | Ignore |
| Projectile | Trigger (impact) | Trigger | Trigger | Ignore | Ignore |
Événements clés (collisions)
OnHit(attackerId, targetId, hitData)OnPickupCollected(pickupId, collectorId)OnEnteredTrigger(triggerId, entityId)
États (state machine) : joueur, ennemis, jeu
Concept
Les états évitent les “if” contradictoires. On définit des machines à états au minimum pour : (1) l’état global du jeu, (2) le joueur, (3) chaque ennemi.
Continuez dans notre application.
Vous pouvez écouter le livre audio écran éteint, recevoir un certificat gratuit pour ce cours et accéder également à 5 000 autres cours en ligne gratuits.
Ou poursuivez votre lecture ci-dessous...Téléchargez l'application
Contraintes techniques
- GameState :
Menu,Playing,Paused,GameOver,Victory. - PlayerState :
Idle,Run,Jump,Fall,Attack,Hurt,Dead. - EnemyState (ex. patrouilleur) :
Patrol,Chase,Attack,Stunned,Dead. - Chaque transition doit avoir une condition claire (ex.
Hurt → Deadsi HP ≤ 0).
Étapes pratiques
- Écrire la liste des états par entité.
- Pour chaque état : actions à l’entrée, actions à la sortie, mises à jour (tick).
- Définir les transitions autorisées (table ou liste).
- Relier les transitions aux événements (hit, input, fin d’animation, timer).
Paramètres configurables : stratégie “data-driven” pour l’équilibrage
Objectif
Rendre modifiables sans code : vitesses, HP, dégâts, cooldowns, densité d’ennemis, récompenses, timers, paramètres de caméra, etc. Le GDD doit indiquer où vivent ces valeurs et comment elles sont chargées.
Règles
- Les valeurs sont stockées dans un asset de configuration (JSON, YAML, ScriptableObject, table interne) versionné.
- Une valeur doit avoir : nom stable, unité (secondes, unités/s), valeur par défaut, plage recommandée.
- Les paramètres sont séparés en : globaux (communs) et par entité (joueur, ennemi, projectile, niveau).
Étapes pratiques (workflow)
- Créer un fichier
GameConfig(global) et des fichiersLevelConfig/EnemyConfig. - Charger la config au démarrage (menu) et la mettre en cache.
- Au chargement d’un niveau, charger
LevelConfigcorrespondant àlevelId. - Lors du spawn d’une entité, injecter sa config (par
enemyTypeId).
Variables globales vs paramètres par entité
Variables globales (exemples)
gravity(float)timeScale(float, utilisé pour pause/slow)maxLives(int) ou règle équivalentedefaultInvulnerabilityTime(float)audioMasterVolume,audioSfxVolume,audioMusicVolume(0..1)language(string)
Paramètres par entité (exemples)
- Joueur :
moveSpeed,jumpForce,maxHp,attackCooldown,hurtKnockback. - Ennemi :
maxHp,contactDamage,patrolSpeed,aggroRange,attackRange,dropTableId. - Projectile :
speed,damage,lifeTime,pierceCount.
Événements clés du gameplay (niveau, checkpoint, fin de partie)
Liste d’événements à standardiser
OnLevelStart(levelId, spawnPointId): initialise HUD, timers, spawns.OnCheckpointReached(levelId, checkpointId): met à jour respawn + sauvegarde.OnPlayerDeath(cause): déclenche respawn ou game over.OnRespawn(levelId, checkpointId): replace joueur, réinitialise certains éléments selon règle.OnLevelCompleted(levelId, stats): progression + écran de fin.OnGameOver(runStats): fin de partie.
Règles d’implémentation (checkpoint minimal)
- Chaque checkpoint a un
checkpointIdunique dans le niveau. - Quand le joueur entre dans la zone : déclencher
OnCheckpointReached. - Stocker
lastCheckpointIddans la progression sauvegardée. - Au respawn : utiliser
SpawnPointIdassocié au checkpoint.
Livrables à inclure dans le GDD (section technique)
1) Liste des systèmes à implémenter (minimum)
- SceneManager : chargement/transition + passage de paramètres.
- InputManager : actions + contextes (UI/Gameplay).
- SaveManager : progression + options + versionnement.
- Collision/Physics Setup : couches + triggers + matrice.
- State Machines : game state + player state + enemy state.
- Spawner : instanciation entités depuis données (niveau).
- EventBus (ou équivalent) : publication/abonnement aux événements clés.
- Config Loader : chargement des assets de données (global/level/entity).
2) Contrat de données (champs nécessaires)
Le contrat ci-dessous sert de référence : les développeurs savent quels champs attendre, et les designers savent quoi remplir.
{ "gameConfig": { "saveVersion": 1, "gravity": 30.0, "defaultInvulnerabilityTime": 0.8, "maxLives": 3 }, "options": { "audioMaster": 0.9, "audioMusic": 0.7, "audioSfx": 0.8, "screenShake": true, "language": "fr" }, "progress": { "unlockedLevelIds": ["level_01"], "lastPlayedLevelId": "level_01", "checkpointByLevel": { "level_01": "cp_02" } }}Contrat LevelConfig (minimum)
{ "levelId": "level_01", "displayName": "Niveau 1", "timeLimitSec": 0, "spawnPoints": [ {"id": "start", "x": 2.0, "y": 1.0}, {"id": "cp_02", "x": 18.0, "y": 1.0} ], "checkpoints": [ {"checkpointId": "cp_02", "triggerRect": {"x": 17.5, "y": 0.5, "w": 2.0, "h": 2.0}, "spawnPointId": "cp_02"} ], "entities": [ {"entityId": "e_001", "type": "enemy", "enemyTypeId": "enemy_patroller", "x": 10.0, "y": 1.0}, {"entityId": "p_001", "type": "pickup", "pickupTypeId": "coin", "x": 6.0, "y": 1.0} ], "winCondition": {"type": "reachExit", "exitRect": {"x": 28.0, "y": 0.0, "w": 2.0, "h": 3.0}}, "loseCondition": {"type": "noLives"}}Contrat EnemyConfig (minimum)
{ "enemyTypeId": "enemy_patroller", "maxHp": 3, "contactDamage": 1, "move": { "patrolSpeed": 2.0, "patrolDistance": 4.0, "turnCooldownSec": 0.2 }, "senses": { "aggroRange": 6.0, "loseAggroRange": 8.0 }, "attack": { "attackRange": 1.2, "attackCooldownSec": 1.0, "windupSec": 0.2 }, "drops": { "dropTableId": "basic_enemy" }}Exemples complets : paramètres pour 1 niveau et 1 ennemi
Exemple 1 — LevelConfig : level_01 (simple, testable)
But : fournir un niveau jouable avec un checkpoint, quelques entités, et une condition de victoire claire. Les valeurs sont volontairement simples pour faciliter l’itération.
{ "levelId": "level_01", "displayName": "Niveau 1", "timeLimitSec": 0, "spawnPoints": [ {"id": "start", "x": 1.5, "y": 1.0}, {"id": "cp_01", "x": 12.0, "y": 1.0} ], "checkpoints": [ {"checkpointId": "cp_01", "triggerRect": {"x": 11.5, "y": 0.5, "w": 2.0, "h": 2.0}, "spawnPointId": "cp_01"} ], "entities": [ {"entityId": "enemy_01", "type": "enemy", "enemyTypeId": "enemy_patroller", "x": 7.0, "y": 1.0}, {"entityId": "enemy_02", "type": "enemy", "enemyTypeId": "enemy_patroller", "x": 16.0, "y": 1.0}, {"entityId": "coin_01", "type": "pickup", "pickupTypeId": "coin", "x": 4.0, "y": 2.0} ], "winCondition": {"type": "reachExit", "exitRect": {"x": 22.0, "y": 0.0, "w": 2.0, "h": 3.0}}, "loseCondition": {"type": "noLives"}}Exemple 2 — EnemyConfig : enemy_patroller (ennemi de base)
But : un ennemi qui patrouille, poursuit si le joueur s’approche, et inflige des dégâts au contact ou via une attaque courte (selon votre règle). Les champs ci-dessous permettent d’ajuster la difficulté sans toucher au code.
{ "enemyTypeId": "enemy_patroller", "maxHp": 3, "contactDamage": 1, "invulnerabilityOnHitSec": 0.1, "move": { "patrolSpeed": 1.8, "patrolDistance": 3.5, "chaseSpeed": 2.4, "turnCooldownSec": 0.15 }, "senses": { "aggroRange": 5.5, "loseAggroRange": 7.5, "lineOfSightRequired": false }, "attack": { "mode": "contactOrMelee", "attackRange": 1.0, "attackCooldownSec": 1.2, "windupSec": 0.15, "hitbox": {"x": 0.8, "y": 0.6, "w": 1.0, "h": 1.0} }, "drops": { "dropTableId": "basic_enemy", "dropChance": 0.35 }}