Zustandsautomaten: Zustandsobjekt versus sequentielle Prüfung: Was sind die Vor- / Nachteile?

8

Ich weiß nicht viel über Finite-State-Maschinen in der KI oder andere Spielverhaltensweisen im Spiel, außer diesem kurzen Tutorial mit einem Miner: http://www.ai-junkie.com/architecture/state_driven/tut_state1.html, das objektorientiert ist.

Ich weiß nicht wirklich, ob dieses Tutorial das Zustandsmuster beschreibt oder nicht. Was denkst du?

Ich spreche nicht über andere eher arithmetisch orientierte Dinge wie Lenkung oder Physik oder Wegfindung oder Kollisionen, sondern über Spielelogik, zustandsgesteuerte KI und Dinge, die viele gleichzeitige Zustände und ifs und / oder switches beinhalten

Was sind die Vor- und Nachteile der Verwendung eines Zustandsmusters oder einer sequentiellen Überprüfung einer einfachen Zustandsstruktur wie dieser:

struct States
{
bool is_walking, is_running, holds_a_weapon, is_crouch;
int weapon_id, int id_team;
};

void HandleStates (States state)
{
//etc
}
Jokoon
quelle
2
Ich denke, Sie müssen Ihre Frage möglicherweise etwas besser formulieren, aber eine schnelle Antwort auf die obigen Fragen, damit Sie dies tun können, ist im Allgemeinen, dass der Status die If-Prüfungen entfernt. switch (state) {case blah}, um eine Sprungtabelle zu erstellen, oder meine persönliche Lieblingsmethode, Funktionszeiger oder Delegaten auf einem Stapel oder einer Warteschlange, wenn AI zu dem zurückkehren soll, was sie zuvor getan haben, oder zum nächsten Schritt übergehen soll. ..
James

Antworten:

10

Ich werde versuchen, dies so gut wie möglich zu beantworten, aber es gibt bestimmte "Best Practices", bei denen ich mir nicht sicher bin, aber ich werde versuchen, sie so sauber wie möglich aufzuschlüsseln.

FSMs

Erstens stammt das Miner-Tutorial aus dem Programmierspiel AI by Example von Mat Buckland (das ich als Einführung in AI empfehlen sollte). Er verwendet für jeden Zustand eine Aufzählung, KEINE Struktur. Mit der Struktur in Ihrem Beispiel haben Sie Boolesche Werte als Status, sodass Sie eine beliebige Anzahl davon gleichzeitig aktivieren können. Dies kann zu einem gewünschten Verhalten führen, führt jedoch bei FSMs (Finite State Machines) häufig zu unerwünschtem Verhalten.

Zum Beispiel:

enum
{
WANDER_AROUND,
ATTACK,
RUN_AWAY,
};

Zweitens beschreibt er Staaten nicht nur so. Ich persönlich bevorzuge (je nach Situation) die Erstellung einer abstrakten Klasse namens State mit den Funktionen Enter (), Exit () und Update (). Dann erstellen Sie meine Zustände als Unterklassen der Zustandsklasse.

Wie dieses Bild (tatsächlich auf Seite 2 dieses Links zu finden): Alt-Text

Zustandsmuster

Meiner persönlichen Meinung nach ist das Zustandsmuster nur ein Teil des Software-Designs, bei dem die Software eine Reihe von Zuständen aufweist. Die Implementierung liegt beim Entwickler. Ich glaube nicht, dass es einen richtigen Unterschied zwischen der Verwendung einer großen switch-Anweisung oder der Erstellung einer vollständigen Zustandsmaschine gibt, um alle Ihre Zustände auszuführen, wie ich oben beschrieben habe. Sie machen im Wesentlichen das Gleiche. In dieser Hinsicht lautet die Antwort auf eine Ihrer Fragen Ja. Ich glaube, diese Seite beschreibt das Zustandsmuster.

Für und Wider

Jede Methode, mit der Sie ein zustandsgesteuertes Design implementieren, hat Vor- und Nachteile.

Verwenden einer If / Else- oder Switch-Anweisung

Vorteile:

  • Sehr einfach, Zustände von Zuständen hinzuzufügen und zu überprüfen
  • Kann sehr schnell prototypisiert werden

Nachteile:

  • Wenn Sie eine Menge Zustände haben, kann es sehr hässlich werden, sehr schnell.
  • Das Verfolgen von Übergängen, Effekten beim Ein- / Verlassen des Zustands oder von spezifischen Zuständen ist schwierig

Verwendung einer objektorientierten Zustandsmaschine

Vorteile:

  • Sehr erweiterbar - Sie müssen lediglich einen neuen Status erstellen, der die abstrakte Statusklasse erbt
  • Einfach zu warten - Sie müssen sich keine Gedanken über Spaghetti-Code machen, da sich jeder Status in seiner eigenen Klasse befindet. Sie können die mit diesem Status verbundenen Bedingungen leicht anzeigen, ohne sich um die anderen Zustände kümmern zu müssen.
  • Intuitiv - Wenn Sie an einem Teamprojekt mit dieser Art von Zustandsmaschine arbeiten, ist dies für die Person, die Ihren Code liest, viel einfacher. Sie müssen nicht Code für Code durchlesen, um zu einem bestimmten Zustand zu gelangen ("Programmieren Sie immer so, als ob der Programmierer, der Ihren Code verwaltet, ein Psychopath ist, der weiß, wo Sie leben!" :))

Nachteile:

  • Leichte Lernkurve - Es kann eine Weile dauern, bis dieses Design Ihren Kopf bei der Implementierung vollständig rund macht
  • Ich kann ehrlich gesagt nicht mehr daran denken, da ich diesen Weg bevorzuge, aber wenn jemand etwas hinzufügen möchte, kommentiere einfach und ich werde sie hinzufügen.

Ich hoffe das beantwortet alle deine Fragen. Tatsächlich habe ich gerade meine Kopie von Programming Game AI by Example geöffnet und Mat erwähnt, dass die Zustandsmaschine als "State Design Pattern" bekannt ist. Persönlich bin ich anderer Meinung, aber jedem sein eigenes.

Ich hoffe es hilft :)

Ray Dey
quelle
1
+1 Dies beschreibt im Wesentlichen, wie ich meine Zustandsmaschine erstellt habe. Es funktioniert gut.
Kyle C
Könnten Sie argumentieren, dass das Muster der "objektorientierten Zustandsmaschine" einen Leistungseinfluss hat - so gering es auch sein mag?
Noob Saibot
@ NoobSaibot Ja, aber das könnte man über alles streiten. Das if-else könnte unter einer schlechten Verzweigungsvorhersage leiden, das oben beschriebene Zustandsmuster kann unter dem Overhead der vtable-Suche leiden. Beides ist unwahrscheinlich, es sei denn, Sie haben eine Menge Staaten. Die eigentliche Antwort auf Ihre Frage lautet also "es kommt darauf an".
Ray Dey