Spielzustand-Automaten
Bitte beachte, dass dieser Artikel noch unvollständig ist! Hilf mit, ihn fertigzustellen.
Näheres dazu findest du ggf. auf der Diskussionsseite. Wenn du der Meinung bist, dass der Artikel vollständig ist, kannst du diesen Hinweis entfernen.
Jeder Spieleentwickler beschäftigt sich früher oder später mit der Frage, wie man am besten mit den verschiedenen Phasen eines Spiels umgeht. Allein wenn man beim Planen schon voraus denkt, fällt einem eine logische Aufteilung auf: Hauptmenü, Charaktererstellung, Hauptspiel, Optionsmenü, Multiplayer-Einstellungen, usw. Zwischen diesen verschiedenen Teilen des Spiels soll natürlich auch problemlos gewechselt werden – und das auch in verschiedenen Kombinationen. Für dieses Problem gibt es eine gute Lösung, welche das Problem der Aufteilung mit Übergangen abstrahiert und abbildet: Spielzustand-Automaten.
Inhaltsverzeichnis |
Grundidee und Architektur
Die Grundidee der Spielzustand-Automaten lässt sich in zwei Klassen teilen: Den Zustands-Manager StateManager und ein Interface State. Jedes Spiel definiert eine Menge an Zuständen in Form einer Klasse, die das Interface State implementiert. Der StateManager kennt und besitzt alle Zustände und identifiziert diese über eine ID. Im Folgenden wird auf beide Klassen näher eingegangen.
State
State definiert ein Interface für den StateManager. Dieses wird von den konkreten Spielzuständen implementiert. Für einen Spielzustand können abhängig von der Situation unterschiedliche Schnittstellen interessant sein. Grundsätzlich können folgende prinzipiell notwendig sein:
- OnInit: Wird das erste Mal zu einem Zustand gewechselt, so wird OnInit aufgerufen. Gelöst ist das, indem die Methode IsInitialized am Anfang false liefert. Nach dem Aufruf von OnInit ist dies nicht mehr der Fall.
- IsInitialized: Diese Methode liefert true zurück, wenn der Zustand schon initialisiert ist. Das ist nach OnInit der Fall.
- OnEnter: Der StateManager ruft diese Methode auf, wenn von einem anderen Zustand zu diesem Zustand gewechselt wird. Dadurch können z.B. Variablen zurückgesetzt, Eingangsanimationen gestartet oder ein Musikstück abgespielt werden.
- OnLeave: Bei der Einleitung eines Zustandswechsels wird, bevor der neue Zustand gesetzt wird, OnLeave vom noch aktuellen Zustand aufgerufen. Dadurch können wichtige Nacharbeiten durchgeführt werden (Musik stoppen, Ressourcen freigeben, ...).
- OnUpdate: In dieser Funktion wird die Logik des Zustands berechnet. Im Falle des Zustands Spiel werden üblicherweise KI, Animationen und Physik aktualisiert.
- OnRender: Hier findet das gesamte Zeichnen für den aktuellen Zustand statt.
- NextState: Liefert den nächsten Zustand, der bei einem Zustandswechsel gewählt werden soll.
StateManager
Der StateManager verwaltet alle für das Spiel möglichen Zustände. Dazu werden ihm alle Zustände durch AddState bekannt gemacht. Für den StateManager ist immer genau ein Zustand aktuell. Dieser lässt sich mit der Methode SetState festlegen.
Prinzipiell verwendet man bei Spielen getrennte Logik für Update- und Render-Funktionalität. Daher unterscheidet der StateManager auch zwischen diesen beiden Vorgängen, indem es getrennte Methoden gibt. Diese rufen vom aktuellen Zustand Update bzw. Render auf.
Beispielimplementierung
State
In C++
class State { public: virtual ~State() { }; virtual void OnInit() = 0; virtual bool IsInitialized() = 0; virtual void OnEnter() = 0; virtual void OnLeave() = 0; virtual bool OnUpdate(float elapsedTime) = 0; virtual void OnRender() = 0; };
In C#
public interface State { void OnInit(); bool IsInitialized { get; } void OnEnter(); void OnLeave(); bool OnUpdate(float elapsedTime); void OnRender(); }