Ich habe am selben Motor wie Coderanger gearbeitet. Ich habe einen anderen Standpunkt. :)
Erstens hatten wir keinen Stapel FSMs - wir hatten einen Stapel Staaten. Ein Stapel von Zuständen bildet eine einzelne FSM. Ich weiß nicht, wie ein Stapel FSMs aussehen würde. Wahrscheinlich zu kompliziert, um irgendetwas Praktisches damit anzufangen.
Mein größtes Problem mit unserer globalen Zustandsmaschine war, dass es sich um einen Stapel von Zuständen und nicht um eine Reihe von Zuständen handelte. Dies bedeutet, dass z. B. ... / MainMenu / Loading anders war als ... / Loading / MainMenu, je nachdem, ob Sie das Hauptmenü vor oder nach dem Ladebildschirm geöffnet haben (das Spiel ist asynchron und das Laden erfolgt hauptsächlich auf Servern) ).
Als zwei Beispiele von Dingen, die dies hässlich machten:
- Es führte zB zum LoadingGameplay-Status, so dass Sie Base / Loading und Base / Gameplay / LoadingGameplay zum Laden innerhalb des Gameplay-Status hatten, die einen Großteil des Codes im normalen Ladezustand (aber nicht alle) wiederholen mussten und etwas mehr hinzufügten ).
- Wir hatten verschiedene Funktionen wie "Wenn im Charakterersteller zum Gameplay wechseln, wenn im Gameplay zur Charakterauswahl wechseln, wenn im Charakterauswahl zum Login zurückkehren", weil wir das gleiche Interface-Fenster in verschiedenen Zuständen anzeigen wollten, aber das Zurück / Vorwärts machen wollten Tasten funktionieren immer noch.
Trotz des Namens war es nicht sehr "global". Die meisten internen Spielesysteme verwendeten es nicht, um ihre internen Zustände zu verfolgen, weil sie nicht wollten, dass sich ihre Zustände mit anderen Systemen herumschlagen. Andere, z. B. das UI-System, könnten es nur verwenden, um den Status in ihre eigenen lokalen Statussysteme zu kopieren. (Ich warne besonders vor dem System für UI-Status. Der UI-Status ist kein Stack, sondern eine echte DAG. Wenn Sie versuchen, eine andere Struktur zu erzwingen, ist die Verwendung von UIs nur frustrierend.)
Wofür war es gut, Aufgaben für die Integration von Code von Infrastruktur-Programmierern zu isolieren, die nicht wussten, wie der Spielfluss tatsächlich aufgebaut ist, sodass Sie dem Typ, der den Patcher schreibt, mitteilen konnten, dass er den Code in Client_Patch_Update einfügt, und dem Typ, der die Grafiken schreibt Wenn Sie "Setzen Sie Ihren Code in Client_MapTransfer_OnEnter" laden, können Sie bestimmte logische Abläufe problemlos austauschen.
Auf einem Nebenprojekt habe ich mehr Glück mit einem Zustand hatte gesetzt anstatt einen Stapel , nicht Angst zu haben mehrere Maschinen für unabhängige Systeme zu machen, und sich weigern , mich in die Falle fallen lassen einen „globalen Zustand“ zu haben, was wirklich ist Nur ein komplizierter Weg, um Dinge über globale Variablen zu synchronisieren - Sicher, Sie werden es in der Nähe einer bestimmten Frist tun, aber entwerfen Sie das nicht als Ihr Ziel . Grundsätzlich ist ein Zustand in einem Spiel kein Stapel, und Zustände in einem Spiel sind nicht alle miteinander verbunden.
Da Funktionszeiger und nicht lokales Verhalten dazu neigen, erschwerte das GSM das Debuggen von Dingen, obwohl das Debuggen derartiger großer Zustandsübergänge nicht sehr viel Spaß machte, bevor wir es hatten. Zustandsmengen anstelle von Zustandsstapeln helfen dies nicht wirklich, aber Sie sollten sich dessen bewusst sein. Virtuelle Funktionen anstelle von Funktionszeigern können dies etwas abmildern.