Alternative zum Game State System?

30

Soweit ich das beurteilen kann, haben die meisten Spiele eine Art "Spielstatus-System", das zwischen den verschiedenen Spielstatus wechselt. Dies können Dinge wie "Intro", "MainMenu", "CharacterSelect", "Loading" und "Game" sein.

Zum einen ist es durchaus sinnvoll, diese in ein staatliches System zu zerlegen. Immerhin sind sie uneinheitlich und müssten ansonsten in einer großen switch-Anweisung stehen, die offensichtlich chaotisch ist. und sie sind sicherlich gut durch ein staatliches System vertreten. Gleichzeitig schaue ich auf den Zustand "Spiel" und frage mich, ob an diesem Ansatz des Zustandssystems etwas nicht stimmt. Weil es wie der Elefant im Raum ist; Es ist RIESIG und offensichtlich, aber niemand stellt den Ansatz des Spielstatus-Systems in Frage.

Mir kommt es albern vor, dass "Spiel" auf die gleiche Ebene gestellt wird wie "Hauptmenü". Es gibt jedoch keine Möglichkeit, den Status "Spiel" aufzulösen.

Ist ein Spielstatus-System der beste Weg? Gibt es eine andere, bessere Technik, um den "Spielstatus" zu verwalten? Ist es in Ordnung, einen Intro-Status zu haben, der einen Film zeichnet und auf die Eingabe wartet, und dann einen Lade-Status, der den Ressourcen-Manager durchläuft, und dann den Spiel-Status, der praktisch alles macht ? Kommt dir das nicht auch irgendwie unausgeglichen vor? Vermisse ich etwas?

Ricket
quelle

Antworten:

30

Ich glaube, Sie streiten hier nur über Semantik. Es heißt Game State, weil es sich wie eine endliche Zustandsmaschine verhält , mit einer endlichen Anzahl von Zuständen und Übergängen zwischen ihnen. Das 'Spiel' im 'Spielstatus-System' bezieht sich auf das Gesamtsystem, wobei 'Laden', 'Hauptmenü' usw. Status des Spiels sind. Diese können leicht als "Szenen" oder "Bildschirme" oder "Ebenen" bezeichnet werden. Es ist nur Semantik.

Ich bin mir nicht sicher, ob ein strenger FSM mehr gilt. In meinen Implementierungen bezeichne ich Zustände als "Bildschirme" und erlaube ihnen, stapelbar zu sein - dh. Bildschirme können über andere Bildschirme gezogen werden, um zu steuern, ob darunter liegende Bildschirme aktualisiert oder gezeichnet werden. Auf diese Weise kann ich mehrere Bildschirme gleichzeitig mit eigenständiger Logik und Code für diesen Bildschirm aktivieren, ohne dass ich mich um einen anderen Bildschirm kümmern muss.

Zum Beispiel könnte ein Pausenbildschirm über meinem Hauptspielbildschirm geöffnet werden, der Updates nicht zulässt, aber das Zeichnen unter sich zulässt. Ein Charakter-Inventarbildschirm kann sowohl das Zeichnen als auch das Aktualisieren ermöglichen - das Spiel wird also weiter gespielt, während Sie an Ihrem Inventar arbeiten.

DrDeth
quelle
genau so sollte es gemacht werden. Bildschirme sollten mehrere andere Bildschirme in einer baumartigen Architektur enthalten können. Ihr Programm enthält also einen Spielbildschirm, der einen Pausenmenübildschirm enthält, der einen Audioeinstellungsbildschirm und einen Spieleinstellungsbildschirm enthält. etc
Iain
1
Ich würde gerne Beispiel-Quellcode dafür sehen! (Vorzugsweise in C ++ / C # / Java)
Zolomon
1
Leider habe ich im Moment nur Produktionscode, aber es gibt ein ähnliches Konzept im XNA Game State-Beispiel: creators.xna.com/en-GB/samples/gamestatemanagement
DrDeth
7

Sicher, der Spielstatus wäre riesig, aber es gibt keinen Grund, warum der Spielstatus selbst keine Zustandsmaschine zur Verwaltung seiner Daten enthalten kann. Hierarchische Zustandsautomaten sind nützlich.

Tetrade
quelle
4

Ich stelle mir immer gerne jeden "Zustand" als "Szene" vor. Das Eröffnungsvideo ist also nur eine statische Szene. Die Credits sind eine Szene. Das Menü ist eine Szene. Der einzige Unterschied zwischen allen besteht in der Interaktivität und der Spielelogik.

Anthony
quelle
3

Damit habe ich eigentlich auch Probleme.

Nehmen wir an, Sie haben ein Spiel.

Anstatt zu machen ‚Game‘ ein Zustand wie ‚Laden‘, ‚Hauptmenü‘ usw. - IMO es besser ist , Spiel zu lassen , hat mehrere Staaten:

"Laden" - "Menü anzeigen" - "Angehalten" usw.

Das Spiel läuft noch, aber wenn das Hauptmenü angezeigt wird, befindet es sich im Modus "Menü anzeigen".

Und wenn sich das Spiel in keinem bestimmten Zustand befindet, läuft es einfach.

Zumindest für mich ist das viel sinnvoller. :)

jacmoe
quelle
Genau. Niemand möchte den Game-State verlassen, nur um in den Pause-State zu gelangen . Auf der anderen Seite: Es ist immer noch ein staatliches System .. nur verschachtelt :)
Bummzack
2

Ein Online-Programm (im herkömmlichen Sinne von Online, dh, es wird ständig ausgeführt und reagiert auf Eingaben, anstatt dass es mit dem Internet verbunden ist) besteht normalerweise aus drei Dingen:

  • Eingabeerfassung und -verarbeitung
  • Aktualisierung der Logik
  • Ausgabe

Im Allgemeinen sind diese 3 verwandt und ändern sich gleichzeitig. Wenn Sie beispielsweise einen Begrüßungsbildschirm anzeigen, ordnen Sie alle Tasten einem Befehl zum Schließen des Bildschirms zu, und die Aktualisierung blendet möglicherweise eine Grafik langsam ein, wobei die Ausgabe nur diese Grafik anzeigt. Beim Spielen eines Spiels werden die Tasten möglicherweise unterschiedlichen Befehlen zugeordnet, und das Update ändert die Eigenschaften vieler Objekte im Spiel.

Wenn Sie es so betrachten, ist es sinnvoll, ein Intro von der Charaktererstellung und vom eigentlichen Spiel zu trennen: Jedes hat seine eigenen Eingabe-, Aktualisierungs- und Ausgaberegeln. Sie sind fast wie eigenständige Programme, die Daten und Bibliothekscode gemeinsam nutzen. Aus diesem Grund ist es in der Regel sinnvoll, nur einen Spielstatus zu haben, da das Gameplay durchgehend ziemlich homogen ist.

Natürlich gibt es keinen Grund, warum Sie dort nicht mehrere Zustände haben könnten, wenn Sie tatsächlich verschiedene Arten von Spiel haben (z. B. ein RPG-Beispiel - Weltkarte, Stadtplan, Zwischensequenz, Kampf), mit unterschiedlichen Eingaben, Aktualisierungen und Ausgaben auch anstelle von nur 1 Spielstatus. Aber es hängt von deinem Spiel ab.

Kylotan
quelle
1

Ich sehe es anders. "Menü", "HighScores", "Credits" oder was auch immer Sie haben, könnten als eine andere Ebene betrachtet werden, und dann ist dieser Zustand nicht unbedingt leichter als Ihr "Spiel" -Zustand (der Spielzustand hat einfach mehr Entitäten im Allgemeinen). und andere, aber am Ende ist es nur eine andere Ebene, auf der die Entitäten mehr prädikatibles Verhalten zeigen und die "Karten" im Allgemeinen weniger kompliziert sind.
Wenn Sie diese Änderung in Ihrem Denken vornehmen, werden Sie definitiv aus dem "langweiligen Menü" -Syndrom herausgezogen.

Kaj
quelle
Ich wollte dasselbe sagen ... Alle meine Menüs, Bildschirme, was auch immer, sind nur eine andere Ebene.
Speeder
1

In meinem Spiel habe ich:

Der Execution Manager , der die Anwendung (das Spiel) initialisiert, Ressourcen lädt, Ressourcen beim Beenden der Anwendung freigibt usw. Er initialisiert Application Engine, GameViewEngine, GameLogicEngine.

Game State Manager , der sich in der GameLogicEngine befindet und für die Steuerung der Dinge im Zusammenhang mit der Hauptschleife des Spiels verantwortlich ist: Kollisionserkennung, Physikberechnung, Tastaturlesen, mathematische Operationen usw.

Anfangs hatte ich nur einen Game State Manager, der Teil meiner GameLogicEngine war. Ich hatte jedoch einige Schwierigkeiten, die Initialisierung der Hauptsubsysteme (GameLogic, ApplicationEngine, ...) zu kontrollieren. Es hätte getan werden können, aber es war unordentlicher, imo.

Jetzt sieht es für mich transparenter aus und ich bin mit dem Design zufrieden.

Bunkai.Satori
quelle
0

Benenne den 'Game'-Status in' Gameplay 'um. Dann scheint deine Logik besser zu sein; Sie hören auf zu spielen, um zum Menü zu gelangen: Sie verlassen den Gameplay-Status, um in den MainMenu-Status zu gelangen.

Ich denke auch, dass Dinge wie Pause, bei denen sich das Spiel im selben Zustand wie bei der Pause befinden müsste, keine getrennten Zustände sein sollten. Vielleicht Kinderzustände und Nisten? Das Gameplay hat ein Pausenmenü.

Die kommunistische Ente
quelle
0

Ich denke, dass es eine gute Methode gibt, die als Spielstatusstapel bezeichnet wird. Ich habe keine Zeitungen oder Artikel darüber gesehen, aber es hat sich ein bisschen lautstark verbreitet. Im Wesentlichen wird der oberste Spielstatus auf dem Stapel zuerst aufgerufen und kann mit Eingabe / Rendern usw. alles Mögliche tun. Der oberste Spielstatus ist der einzige, der Push- oder Pop-Status zulässt.

In meiner Engine sind Spielzustände eigentlich nur Listen von Spieleinheiten. Ich habe dann Entitäten, die als Menüs arbeiten. Meine Menüzustände unterbrechen entweder das Spiel (indem der nächste Gegenstand auf dem Stapel nicht aktualisiert wird), aber lassen Sie die anderen Zustände ihre Modelle an den Renderer senden, sodass mein Pausenmenü (das nicht den gesamten Bildschirm abdeckt) immer noch angezeigt wird hat das spiel rendern im rücken.

Ich hoffe, das gibt eine Vorstellung von einem etwas anderen System, das nicht auf einer Zustandsmaschine basiert.

Simon
quelle
0

Ist es in Ordnung, einen Intro-Status zu haben, der einen Film zeichnet und auf die Eingabe wartet, und dann einen Lade-Status, der den Ressourcen-Manager durchläuft, und dann den Spiel-Status, der praktisch alles macht? Kommt dir das nicht auch irgendwie unausgeglichen vor? Vermisse ich etwas?

Das ist vollkommen in Ordnung. Oder zumindest ist es eine Verbesserung gegenüber "einem großen hässlichen Schalter, abhängig vom Zustand des Spiels".

Ich möchte darauf hinweisen, dass Sie in den meisten Spielen bereits eine Art Finite-State-Maschine benötigen, um mit einfacher Entity-KI umgehen zu können. Das typische Beispiel sind Feinde, die sich im Ruhezustand befinden, angreifen oder sterben.

Wenn Sie eine ausreichend abstrahierte Zustandsmaschine haben, können Sie diese sowohl für das Spielobjekt als auch für Ihre KI wiederverwenden. plötzlich "investieren" Sie nicht mehr viel in den Spielstatus - stattdessen verwenden Sie den Code, den Sie sowieso verwendet haben.

Schamloses Selbst-Plug-In: Ich habe eine solche Finite-State-Maschine in meine Lua-Spielebibliothek MiddleClass (konkret das Add-On MindState) implementiert. Hier erfahren Sie, wie Sie damit einen Spielstatus erstellen .

egarcia
quelle
0

Ein anderer Ansatz besteht darin, ein Konzept aus der Welt der funktionalen Programmierung zu verwenden, das als diskriminierte Union bezeichnet wird . Während diese normalerweise in FP-Sprachen vorkommen, können Sie sie mithilfe von Klassen emulieren .

Grundsätzlich ist eine diskriminierte Union ein Typ, der immer einer der nFälle ist, und die gespeicherten Daten können von Fall zu Fall variieren.

Beispielsweise:

type GameState =
  | Menu of MenuState
  | Playing of SimulationState

Hier kann unser GameStateTyp entweder Menuoder sein Playing. Wenn dies der Fall ist Menu, enthält es ein MenuStateObjekt. Wenn dies der Fall ist Playing, enthält es ein SimulationStateObjekt.

Zum Update würden wir matchauf den Stand, und eine andere Funktion entsprechend aufrufen:

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

  // Mutate the current state
  gameState <- nextState

Und ähnlich zum Rendern:

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

Ein Vorteil dieses Ansatzes besteht darin, dass Sie Dinge über Zustände (wie Ressourcen) hinweg einfacher handhaben können, ohne Globals oder "Service" -Objekte zu übergeben.

sdgfsdh
quelle