Avant de débuter je tiens à préciser que ce petit tutoriel n’est en rien une solution miracle et adaptée à tous les projets. Gardez en tête en lisant ce tutoriel -et si possible quand vous lisez n’importe quel tutoriel- que les bonnes pratiques n’existent pas en programmation. Chaque code a ses avantages et ses inconvénients qui peuvent varier en fonction de la plateforme, les besoins des utilisateurs, les délais à respecter, etc… Le plus important, c’est que votre code fasse son boulot, et qu’il le fasse de manière efficace et performante.
Vous vous êtes peut être déjà demandés comment sont faits les jeux vidéos, quelles en sont les bases, et de quelles briques ils sont formés ? Je vais essayer de vous expliquer à travers cet article, et d’autres à venir, les rudiments à savoir pour commencer à développer votre propre jeu vidéo.
Notre premier article sera consacré aux Game States. Nous allons dans un premier temps essayer comprendre le principe d’état appliqué au jeu vidéo, puis nous verrons comment gérer ces différents états.
Qu’est ce qu’un Game State ?
Cette notion de game state peut paraître un peu abstraite lorsque l’on débute, mais elle est très simple. Les game states sont les différents états que va prendre votre jeu au cours d’une partie. Le joueur rencontrera dans une partie différents game states sans parfois s’en rendre compte. Le menu principal, une phase de jeu, une phase de combat à l’intérieur de la phase de jeu, une carte du monde, un menu de dialogue, le menu en jeu, la pause, l’écran des high scores sont autant de game states possibles.
Comment mettre en place la gestion des game states ?
Une des manière de gérer les game states assez populaire, et très simple à comprendre est celle de la Game State Stack.
Son principe est exactement calqué sur celui d’une Stack. Nous allons empiler nos différents états dans une stack, et nous mettrons à jour et afficherons l’état en tête de pile.
Pour gérer notre game state stack, nous allons utiliser trois méthodes : Add, Pop et Set.
Les méthodes Add (Push) et Pop sont directement inspirées des structures de données LIFO (ou Stack)
Add va nous permettre de rajouter un état dans la pile. Pop va nous permettre de retirer un état de la pile.
La méthode Set est simplement la combinaison de Pop et Add. On va tout d’abord appeler Pop et retirer l’état courant de la pile. Ensuite nous allons ajouter un nouvel état à la place de l’ancien.
Pourquoi différencier Add/Pop et set ? Afin d’être plus flexible. En effet, nous allons parfois vouloir simplement rajouter un état provisoirement puis reprendre l’état précédent sans aucune perte de donnée.
Schématisons tout cela. Prenons comme cas un jeu qui a pour états un menu principal, une phase de jeu, une pause, et un menu en jeu. Voila à quoi pourrait ressembler notre jeu :
Comme vous pouvez le voir, nous avons utiliser différentes méthodes pour relier nos différents états.
Nous passons du menu principal à la phase de jeu grâce à la méthode Set. Nous passons le jeu en pause ou consultons le menu en jeu en utilisant la méthode Add, nous revenons au jeu avec la méthode Pop. Enfin, nous passons du menu en jeu au menu principal avec la méthode Set.
Pour être sûr de bien comprendre, nous allons voir le nombre d’états que nous aurons dans la game state stack pour chaque état :
- Menu Principal : 1
- Phase de Jeu : 1
- Pause : 2
- Menu en jeu : 2
Note : Quand nous allons passer du menu en jeu au menu principal, nous devrons veiller à bien détruire les deux states, sinon, nous aurons une fuite mémoire.
Passons au code !
Nous allons maintenant implémenter notre gestionnaire de Game State. J’ai choisit de vous présenter ici la manière la plus épurée possible.
La première étape consiste à créer une classe abstraite qui va représenter la base de nos états. Elle est composée des méthodes suivantes :
- Initialize va nous permettre d’initialiser notre état. Elle sera appelée une seule fois quand l’état sera ajouté à la Game state stack.
- Update va nous permettre de mettre à jour l’état. On lui a passé en paramètre un flottant qui représente le temps qui s’est écoulé depuis la précédente mise à jour.
- Draw va nous permettre d’afficher l’état
- Destroy enfin est facultative et nous permet de libérer les ressources allouée par l’état.
Voici le code :
// ============================================================================= /// Classe abstraite servant de base aux game states // ============================================================================= public abstract class GameState { // ========================================================================= /// Initialise le game state // ========================================================================= public abstract void Initialize(); // ========================================================================= /// Détruit le game state // ========================================================================= public virtual void Destroy() {} // ========================================================================= /// Met à jour le game state // ========================================================================= public abstract void Update(float deltatime); // ========================================================================= /// Affiche le game state // ========================================================================= public abstract void Draw(); }
Maintenant, nous allons créer la classe GameStateStack qui va contenir les méthodes que nous avons vu plus haut : Set, Add et Pop. Nous allons également rajouter les méthodes Update et Draw qui vont nous permettre de mettre à jour et dessiner nos différents states.
Afin de stocker nos objets GameState, nous allons utiliser le type générique Stack<GameState>.
// ============================================================================= /// Game State Stack // ============================================================================= public class GameStateStack { // ========================================================================= /// Remplace l'état courant par un nouvel état. /// S'il y a plusieurs états dans la stack, on les supprime tous // ========================================================================= public void Set(GameState state) { while (States.Count > 0) { Pop(); } Add(state); } // ========================================================================= /// Initialize un état puis l'ajoute à la stack // ========================================================================= public void Add(GameState state) { state.Initialize(); States.Push(state); } // ========================================================================= /// Supprime l'état courant de la stack // ========================================================================= public void Pop() { if (States.Count > 0) { States.Peek().Destroy(); States.Pop(); } } // ========================================================================= /// Met à jour l'état courant // ========================================================================= public void Update(float deltatime) { if (States.Count > 0) { States.Peek().Update(deltatime); } } // ========================================================================= /// Affiche l'état courant // ========================================================================= public void Draw() { if (States.Count > 0) { States.Peek().Draw(); } } // ========================================================================= /// Stack de Game States // ========================================================================= public Stack<GameState> States = new Stack<GameState>(); }
Si vous avez bien suivit, vous devriez retrouver ce que nous avons expliqué plus haut dans ce code. Add ajoute un state à la game state stack, pop supprime le state courant, et Set est une combinaison des deux méthodes précédentes.
Il ne vous reste plus qu’à implémenter vos GameState en héritant de la classe abstraite GameState.
Un exemple ?
Je vous ai préparé un petit exemple en utilisant XNA 4.0.Vous pouvez le télécharger en cliquant ici : GameStateStack
Avant de le lancer ou d’essayer de le compiler, voici deux prérequis :
- Pour lancer l’exécutable, vous devez posséder le XNA Redistributable 4.0.
- Pour compiler la solution, vous devez installer les outils de développement XNA 4.0, disponibles à cette adresse : http://create.msdn.com/en-us/home/getting_started
Note : Le XNA Redistributable 4.0 est inclus dans les outils de développement, vous n’aurez pas besoin de l’installer si vous installez les outils de développement.
Pour aller plus loin.
Vous pourrez trouver une internet quelques autres exemples de Game State Management, dont deux particulièrement intéressant sur App Hub, la plateforme de Microsoft dédiée au développement XNA.
Game State Management : Qui vous présente une autre manière d’aborder le problème, et rajoute quelques spécificités comme les transitions entre états.
Network Game State Management : Cet exemple applique le concept aux jeux en réseau.

