Alternative au Game State System?


30

Pour autant que je sache, la plupart des jeux ont une sorte de "système d'état du jeu" qui bascule entre les différents états du jeu; il peut s'agir de choses comme "Intro", "MainMenu", "CharacterSelect", "Loading" et "Game".

D'une part, il est tout à fait logique de les séparer en un système d'État. Après tout, ils sont disparates et devraient autrement être dans une grande instruction switch, ce qui est évidemment désordonné; et ils sont certainement bien représentés par un système étatique. Mais en même temps, je regarde l'état "Game" et je me demande s'il y a quelque chose qui ne va pas dans cette approche du système d'état. Parce que c'est comme l'éléphant dans la pièce; c'est ÉNORME et évident, mais personne ne remet en question l'approche du système d'état du jeu.

Il me semble idiot que "Game" soit mis au même niveau que "Main Menu". Pourtant, il n'y a aucun moyen de briser l'état "Jeu".

Un système d'état du jeu est-il la meilleure solution? Existe-t-il une technique différente et meilleure pour gérer, enfin, "l'état du jeu"? Est-il correct d'avoir un état d'introduction qui dessine un film et écoute l'entrée, puis un état de chargement qui boucle sur le gestionnaire de ressources, puis l'état du jeu qui fait pratiquement tout ? Cela ne vous semble-t-il pas en quelque sorte déséquilibré? Suis-je en train de manquer quelque chose?

Réponses:


30

Je pense que vous discutez simplement de sémantique ici. On l'appelle Game State car il se comporte comme une machine à états finis , avec un nombre fini d'états et de transitions entre eux. Le «Jeu» dans «Game State System» se réfère au système global, avec «Loading», «MainMenu» etc. étant les états du jeu. Ceux-ci pourraient facilement être appelés «scènes» ou «écrans» ou «niveaux». C'est juste de la sémantique.

Je ne suis pas sûr qu'un FSM strict s'applique plus. Dans mes implémentations, j'appelle les états «écrans» et je les autorise à être empilables, c'est-à-dire. les écrans peuvent être dessinés au-dessus d'autres écrans, contrôlant si les écrans en dessous sont mis à jour ou dessinés. De cette façon, je peux avoir plusieurs écrans actifs en même temps avec une logique et un code autonomes spécifiques à cet écran, sans avoir à me soucier d'un autre écran.

Un écran Pause, par exemple, pourrait être ouvert au-dessus de mon écran de jeu principal qui interdit les mises à jour, mais permet de dessiner en dessous de lui-même. Un écran d'inventaire des personnages pourrait permettre à la fois de dessiner et de mettre à jour - donc le jeu continue de jouer pendant que vous travaillez dans votre inventaire.


c'est exactement ainsi qu'il faut procéder. Les écrans doivent pouvoir contenir plusieurs autres écrans dans une architecture arborescente. Votre programme contient donc un écran de jeu, qui contient un écran de menu de pause, qui contient un écran de paramètres audio et un écran de paramètres de jeu. etc
Iain

1
J'aimerais voir un exemple de code source pour cela! (De préférence en C ++ / C # / Java)
Zolomon

1
Malheureusement, je ne dispose que le code de production au moment, mais il y a un concept similaire dans l'échantillon XNA Game Etat: creators.xna.com/en-GB/samples/gamestatemanagement
DrDeth

7

Bien sûr, l'état du jeu serait énorme, mais il n'y a aucune raison que l'état du jeu lui-même ne puisse pas contenir une machine d'état pour gérer ses données. Les machines à états hiérarchiques sont utiles.


4

J'aime toujours penser à chaque "état" comme une "scène". La vidéo d'ouverture est donc une scène, juste statique. Le générique est une scène. Le menu est une scène. La seule différence entre eux est le niveau d'interactivité et la logique de jeu.


3

J'ai aussi des problèmes avec ça, en fait.

Disons que vous avez un jeu.

Au lieu de faire de 'Game' un état comme 'Loading', 'Main Menu', etc. - OMI, il vaut mieux laisser Game avoir plusieurs états:

"Chargement" - "affichage du menu" - "en pause" , etc.

Le jeu est toujours en cours d'exécution, mais lorsqu'il affiche le menu principal, il est en mode «Afficher le menu».

Et lorsque Game n'est pas dans un état particulier, il est simplement en cours d'exécution.

Cela a beaucoup plus de sens, du moins pour moi. :)


Je suis d'accord. Personne ne veut sortir du Game-State juste pour entrer dans le Pause-State . D'un autre côté: c'est toujours un système d'état .. juste imbriqué :)
bummzack

2

Un programme en ligne (au sens traditionnel de «en ligne», c'est-à-dire fonctionnant en permanence et répondant à des entrées, plutôt que de signifier connecté à Internet) se compose généralement de 3 éléments:

  • collecte et gestion des entrées
  • mise à jour de la logique
  • sortie

De manière générale, ces 3 sont liés et changent en même temps. Par exemple, lorsque vous affichez un écran de démarrage, vous pouvez mapper toutes vos touches sur une commande de `` fermeture d'écran '' et la mise à jour peut progressivement estomper un graphique avec la sortie montrant simplement ce graphique. Mais lorsque vous jouez à un jeu, les touches peuvent toutes correspondre à des commandes différentes et la mise à jour modifie les propriétés de nombreux objets dans le jeu.

Lorsque vous le voyez de cette façon, il est logique de séparer une introduction de la création de personnage et du jeu proprement dit: chacun a son propre ensemble de règles d'entrée, de mise à jour et de sortie. Ils sont presque comme des programmes autonomes qui partagent des données et du code de bibliothèque. Et, dans cet esprit, il est généralement logique de n'avoir qu'un seul état de jeu, car le gameplay est assez homogène tout au long.

Bien sûr, si vous avez réellement des types de jeu différents (par exemple, un exemple de RPG - carte du monde, carte de ville, cinématique, combat), avec des entrées, des mises à jour et des sorties différentes, il n'y a aucune raison pour laquelle vous ne pouvez pas avoir plusieurs états là-bas aussi au lieu d'un seul état de jeu. Mais cela dépend de votre jeu.


1

Je le regarde dans l'autre sens. "Menu", "HighScores", "crédits" ou quoi que ce soit, pourrait être considéré comme juste un autre niveau, puis cet état n'est pas nécessairement plus léger que votre état "jeu" (l'état du jeu se trouve simplement avoir plus d'entités en général, et différents, mais en fin de compte, c'est juste un autre niveau où les entités montrent un comportement plus prédictif et les 'cartes' sont généralement moins complexes).
Faire ce changement dans votre pensée vous sort définitivement du syndrome du "menu ennuyeux".


J'allais dire la même chose ... Tous mes menus, écrans, peu importe, ne sont qu'un autre niveau.
speeder

1

Dans mon jeu, j'ai:

Execution Manager , qui initialise l'application (jeu), charge des ressources, libère des ressources à la sortie de l'application, etc. Il initialise Application Engine, GameViewEngine, GameLogicEngine.

Game State Manager , qui réside dans le GameLogicEngine, et est responsable du contrôle des choses liées à la boucle principale du jeu: détection de collision, calcul physique, lecture au clavier, opérations mathématiques, etc.

Au départ, j'avais tendance à n'avoir qu'un seul Game State Manager qui faisait partie de mon GameLogicEngine. Cependant, j'ai eu quelques difficultés avec le contrôle de l'initialisation des sous-systèmes principaux (GameLogic, ApplicationEngine, ...). Cela aurait pu être fait, mais c'était plus compliqué, imo.

Maintenant, les choses me semblent plus transparentes et je suis satisfait du design.


0

Renommez l'état «Jeu» en quelque chose comme «Gameplay». Ensuite, votre logique semble meilleure; Vous arrêtez de jouer pour accéder au menu: vous quittez l'état Gameplay pour passer à l'état MainMenu.

De plus, je pense que des choses comme la pause, qui exigerait que le jeu soit dans le même état que lorsque vous avez mis le jeu en pause, ne devraient pas être des états séparés. Les états des enfants et la nidification, peut-être? Le Gameplay a un menu de pause.


0

Je pense qu'il existe une bonne méthode appelée pile d'état du jeu. Je n'ai vu aucun article ni article à ce sujet, mais il se répand un peu par la voix. Essentiellement, l'état de jeu le plus élevé de la pile est appelé en premier et obtient ce qu'il veut avec l'entrée / le rendu, etc. L'état de jeu le plus élevé est le seul autorisé à pousser ou à faire apparaître des états.

Dans mon moteur, les états de jeu ne sont en fait que des listes d'entités de jeu. J'ai ensuite des entités qui fonctionnent comme des menus. Mes états de menu mettent soit le jeu en pause (en ne mettant pas à jour l'élément suivant sur la pile) mais laissent les autres états pousser leurs modèles vers le moteur de rendu afin que mon menu de pause (qui ne couvre pas tout l'écran) reste a le rendu du jeu dans le dos.

J'espère que cela donne une idée d'un système un peu différent qui n'est pas basé sur une machine à états.


0

Est-il correct d'avoir un état d'introduction qui dessine un film et écoute l'entrée, puis un état de chargement qui boucle sur le gestionnaire de ressources, puis l'état du jeu qui fait pratiquement tout? Cela ne vous semble-t-il pas en quelque sorte déséquilibré? Suis-je en train de manquer quelque chose?

C'est parfaitement bien. Ou du moins, c'est une amélioration par rapport à "avoir un gros interrupteur moche selon l'état du jeu".

Je voudrais souligner que dans la plupart des jeux, vous aurez déjà besoin d'une sorte de machine à états finis pour traiter l'IA d'entité simple. L'exemple typique sont les ennemis qui sont en état de ralenti, attaquant ou mourant.

Si vous avez une machine à états finis suffisamment abstraite, vous pouvez la réutiliser à la fois pour l'objet Jeu et votre IA; tout à coup, vous n'investissez pas beaucoup d'efforts sur l'état du jeu. Au lieu de cela, vous réutilisez du code que vous avez utilisé de toute façon.

Un auto-plug sans vergogne s'ensuit: j'ai implémenté une telle machine à états finis sur ma bibliothèque de jeux Lua, MiddleClass (concrètement, le module complémentaire appelé MindState). Voici comment vous en faites un état du jeu .


0

Une approche différente consiste à utiliser un concept du monde de la programmation fonctionnelle appelé Union Discriminée . Bien que ceux-ci se trouvent généralement dans les langages FP, vous pouvez les émuler à l'aide de classes .

Fondamentalement, une union discriminée est un type qui fait toujours partie des ncas, et les données stockées peuvent varier avec chaque cas.

Par exemple:

type GameState =
  | Menu of MenuState
  | Playing of SimulationState

Ici, notre GameStatetype peut être soit Menuou Playing. Si c'est le cas Menu, il contiendra un MenuStateobjet. Si c'est le cas Playing, il contiendra un SimulationStateobjet.

Pour mettre à jour, nous devrions matchsur l'état, et appeler une fonction différente en conséquence:

let update gameTime = 
  let nextState = 
    match gameState with
    | Menu menuState -> updateMenu gameTime menuState
    | Playing simulationState -> updateSimulation gameTime simulationState

  // Mutate the current state
  gameState <- nextState

Et de même pour le rendu:

let render gameTime = 
  let nextState = 
    match gameState with
    | Menu menuState -> renderMenu menuState
    | Playing simulationState -> renderSimulation simulationState

Un avantage de cette approche est que vous pouvez gérer les choses entre les états (comme les ressources) plus facilement sans globaux ni passer autour des objets "service".

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.