Unlimited WordPress themes, graphics, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Game Development
  2. Programming

Finite-State-Maschinen: Heldenverhalten mit Squad-Muster

by
Difficulty:IntermediateLength:LongLanguages:

German (Deutsch) translation by Nikol Angelowa (you can also view the original English article)

Finite-State-Maschinen und Verhaltensregierung passen perfekt zusammen: Ihre Dynamik ermöglicht die Kombination einfacher Zustände und Kräfte, um komplexe Verhaltensmuster zu erzeugen. In diesem Tutorial erfahren Sie, wie Sie ein Squad-Muster mit einer stapelbasierten Finite-State-Maschine in Kombination mit Steering-Verhalten codieren.

Alle FSM-Symbole von Lorc sind auf http://game-icons.net verfügbar. Assets in der Demo: Top/Down Shoot 'Em Up Spritesheet von takomogames und Alien Breed (esque) Top-Down Tilesheet von SpicyPixel.

Hinweis: Obwohl dieses Tutorial mit AS3 und Flash geschrieben wurde, sollten Sie in fast jeder Spieleentwicklungsumgebung dieselben Techniken und Konzepte verwenden können.


Endergebnis

Nach Abschluss dieses Tutorials können Sie ein Truppmuster implementieren, in dem eine Gruppe von Soldaten dem Anführer folgt, Feinde jagt und Gegenstände plündert:

Squad-Muster implementiert mit stapelbasiertem FSM und Steering-Verhalten. Bewegen Sie den Mauszeiger, um den Anführer zu führen, und klicken Sie, um zu schießen.

Kombination von stapelbasiertem FSM und Steering-Verhalten

Im vorherigen Tutorial über Maschinen mit endlichen Zuständen wurde beschrieben, wie nützlich sie für die Implementierung der Logik der künstlichen Intelligenz sind: Anstatt einen sehr komplexen Stapel von KI-Code zu schreiben, kann die Logik auf eine Reihe einfacher Zustände verteilt werden, von denen jeder sehr spezifische Aufgaben ausführt, wie z vor einem Feind davonlaufen.

Die Kombination von Zuständen führt zu einer ausgeklügelten KI, die jedoch leicht zu verstehen, zu optimieren und zu warten ist. Diese Struktur ist auch eine der Säulen hinter dem Steering-Verhalten: die Kombination einfacher Kräfte, um komplexe Muster zu erzeugen.

Deshalb bilden FSMs und Steering-Verhalten eine großartige Kombination. Die Zustände können verwendet werden, um zu steuern, welche Kräfte auf einen Charakter wirken, wodurch die bereits mächtigen Muster verbessert werden, die mithilfe des Steering-Verhaltens erstellt werden können.


Steuern des Verhaltens mithilfe eines stapelbasierten FSM

Um alle Verhaltensweisen zu organisieren, werden sie über die Staaten verteilt. Jeder Zustand erzeugt eine bestimmte Verhaltenskraft oder eine Reihe von Kräften wie Suchen, Fliehen und Kollisionsvermeidung.

Wenn ein bestimmter Zustand aktiv ist, wird nur die resultierende Kraft auf den Charakter ausgeübt, sodass er sich entsprechend verhält. Wenn der derzeit aktive Zustand beispielsweise runAway ist und seine Kräfte eine Kombination aus flee und collision avoidance sind, flieht der Charakter aus einem Ort und vermeidet dabei Hindernisse.

Die Lenkkräfte werden bei jeder Spielaktualisierung berechnet und dann zum Geschwindigkeitsvektor des Charakters hinzugefügt. Wenn sich der aktive Zustand (und damit das Bewegungsmuster) ändert, wechselt der Charakter nahtlos in das neue Muster, wenn die neuen Kräfte nach jeder Aktualisierung hinzugefügt werden.

Die Dynamik gewährleistet diesen fließenden Übergang. Die Zustände koordinieren lediglich, welche Lenkkräfte zu einem bestimmten Zeitpunkt aktiv sind.


Die Codestruktur

Die Struktur zum Implementieren eines Gruppenmusters kapselt FSMs und Steering-Verhalteninnerhalb der Eigenschaften einer Klasse. Jede Klasse, die eine Entität darstellt, die sich bewegt oder auf andere Weise von Lenkkräften beeinflusst wird, hat eine Eigenschaft namens boid, die eine Instanz der Boid-Klasse ist:

Die Boid-Klasse wurde in der Steering-Verhaltensreihe verwendet und bietet Eigenschaften wie velocity und position (beide mathematische Vektoren) sowie Methoden zum Hinzufügen von Lenkkräften wie seek(), flee() usw.

Eine Entität, die einen stapelbasierten FSM verwendet, hat dieselbe Struktur wie die Ant-Klasse aus dem vorherigen FSM-Lernprogramm: Der stapelbasierte FSM wird von der brain eigenschaft verwaltet und jeder Status wird als Methode implementiert.

Nachfolgend finden Sie die Soldier-Klasse mit Steering-Vverhalten und FSM-Funktionen:


Planung des "Gehirns"

Das Squad-Muster wird mithilfe einer stapelbasierten Finite-State-Maschine implementiert. Die Soldaten, die Mitglieder des Trupps sind, folgen dem Anführer (vom Spieler kontrolliert) und jagen alle in der Nähe befindlichen Feinde.

Wenn ein Feind stirbt, kann er einen Gegenstand fallen lassen, der gut oder schlecht sein kann (ein Medkit bzw. ein Badkit). Ein Soldat wird die Truppformation brechen und in der Nähe gute Gegenstände sammeln oder dem Ort ausweichen, um schlechte Gegenstände zu vermeiden.

Unten finden Sie eine grafische Darstellung des stapelbasierten FSM, der das "Gehirn" des Soldaten steuert:

FSM repräsentiert das Gehirn eines Soldaten.

In den nächsten Abschnitten wird die Implementierung jedes Staates vorgestellt. Alle Codefragmente in diesem Tutorial beschreiben die Hauptidee jedes Schritts, wobei alle Einzelheiten bezüglich der verwendeten Spiel-Engine (in diesem Fall Flixel) weggelassen werden.


Dem Führer folgen

Der erste Zustand, der implementiert wird, ist derjenige, der fast die ganze Zeit aktiv bleibt: Folgen Sie dem Führer. Der Plünderungsteil wird später implementiert, sodass der Soldat im Moment nur dem Anführer follow und den aktuellen Status auf hunt umschaltet, wenn sich ein Feind in der Nähe befindet:

Trotz der Anwesenheit von Feinden wird der Staat, während er aktiv ist, immer eine Kraft erzeugen, um dem Anführer zu folgen, wobei der Anführer dem Verhalten folgt.

Wenn getNearestEnemy() etwas zurückgibt, bedeutet dies, dass sich ein Feind in der Nähe befindet. In diesem Fall wird der hunt zustand durch den Aufruf brain.pushState(hunt) in den Stapel geschoben, wodurch der Soldat aufhört, dem Anführer zu folgen und Feinde zu jagen.

Im Moment kann sich die Implementierung des hunt() - Zustands einfach vom Stapel lösen, so dass die Soldaten nicht im Jagdzustand stecken bleiben:

Beachten Sie, dass keine Informationen an den hunt staat weitergegeben werden, z. B. wer der nächste Feind ist. Diese Informationen müssen vom hunt status selbst gesammelt werden, da sie bestimmen, ob die hunt aktiv bleiben oder sich vom Stapel entfernen soll (wodurch das Steuerelement in den follow status zurückgesetzt wird).

Das bisherige Ergebnis ist eine Gruppe von Soldaten, die dem Anführer folgen (beachten Sie, dass die Soldaten nicht jagen werden, da sich die hunt() -Methode nur von selbst öffnet):

Squad-Muster mit "follow" - und nicht funktionierenden "hunt" -Zuständen. Bewegen Sie den Mauszeiger, um den Anführer zu führen, und klicken Sie, um zu schießen.

Tipp: Jeder Staat sollte dafür verantwortlich sein, seine Existenz zu beenden, indem er sich vom Stapel löst.


Formation brechen und jagen

Der nächste zu implementierende Staat ist die hunt, bei der Soldaten jeden in der Nähe befindlichen Feind jagen. Der Code für hunt() lautet:

Der Staat beginnt mit der Zuweisung aNearestEnemy mit dem nächsten Feind. Wenn aNearestEnemy null ist, bedeutet dies, dass kein Feind in der Nähe ist, sodass der Staat enden muss. Der Aufruf brain.popState() löst den hunt status aus und schaltet den Soldaten in den nächsten Status im Stapel.

Wenn aNearestEnemy nicht null ist, bedeutet dies, dass ein Feind gejagt werden muss und der Staat aktiv bleiben sollte. Der Jagdalgorithmus basiert auf der Entfernung zwischen dem Soldaten und dem Feind: Wenn die Entfernung größer als 80 ist, sucht der Soldat die Position des Feindes. Wenn die Entfernung weniger als 80 beträgt, stellt sich der Soldat dem Feind und schießt im Stillstand.

Da bei jedem Spielupdate hunt() aufgerufen wird, sucht oder erschießt der Soldat diesen Feind, wenn sich ein Feind in der Nähe befindet. Die Entscheidung, sich zu bewegen oder zu schießen, wird dynamisch durch die Entfernung zwischen dem Soldaten und dem Feind gesteuert.

Das Ergebnis ist eine Gruppe von Soldaten, die dem Anführer folgen und in der Nähe befindliche Feinde jagen können:

Squad-Muster mit "follow" und "hunt". Bewegen Sie den Mauszeiger, um den Anführer zu führen, und klicken Sie, um zu schießen.

Plündern und weglaufen

Jedes Mal, wenn ein Feind getötet wird, kann er einen Gegenstand fallen lassen. Der Soldat muss den Gegenstand einsammeln, wenn er gut ist, oder aus dem Gegenstand fliehen, wenn er schlecht ist. Dieses Verhalten wird im zuvor beschriebenen FSM durch zwei Zustände dargestellt:

FSM hebt die Status collectItem und runAway hervor.

Der Status collectItem führt dazu, dass ein Soldat zu dem abgelegten Gegenstand gelangt, während der Status runAway den Soldaten dazu bringt, aus dem Ort des fehlerhaften Gegenstands zu fliehen. Beide Zustände sind fast identisch, der einzige Unterschied ist die Ankunfts- oder Fluchtkraft:

Hier bietet sich eine Optimierung der Übergänge an. Der Code für den Übergang vom Status follow zum Status collectItem oder runAway ist derselbe: Überprüfen Sie, ob sich ein Element in der Nähe befindet, und drücken Sie dann auf den neuen Status.

Der zu pushende Status hängt vom Typ des Elements ab. Infolgedessen kann der Übergang zu collectItem oder runAway als einzelne Methode mit dem Namen checkItemsNearby() implementiert werden:

Diese Methode überprüft das nächste Element. Wenn es gut ist, wird der collectItem-Status ins Gehirn gedrückt. Wenn es schlecht ist, wird der runAway-Status verschoben. Wenn kein Gegenstand zum Sammeln vorhanden ist, führt die Methode nichts aus.

Diese Optimierung ermöglicht die Verwendung von checkItemsNearby(), um den Übergang von einem beliebigen Status zu collectItem oder runAway zu steuern. Laut dem Soldaten FSM besteht dieser Übergang in zwei Staaten: follow und hunt.

Ihre Implementierung kann geringfügig geändert werden, um diesem neuen Übergang Rechnung zu tragen:

Während ein Soldat dem Anführer folgt, sucht er nach Gegenständen in der Nähe. Bei der Jagd auf einen Feind sucht ein Soldat auch nach Gegenständen in der Nähe.

Das Ergebnis ist die Demo unten. Beachten Sie, dass ein Soldat jedes Mal versucht, einen Gegenstand zu sammeln oder ihm auszuweichen, wenn sich einer in der Nähe befindet, obwohl Feinde zu jagen sind und der Anführer ihm folgen muss.

Squad-Muster mit "follow", "hunt", "collectItem" und "runAway". Bewegen Sie den Mauszeiger, um den Anführer zu führen, und klicken Sie, um zu schießen.

Priorisierung von Zuständen und Übergängen

Ein wichtiger Aspekt in Bezug auf Zustände und Übergänge ist die Priorität unter ihnen. Abhängig von der Zeile, in der ein Übergang innerhalb der Implementierung eines Staates platziert wird, ändert sich die Priorität dieses Übergangs.

Schauen Sie sich am Beispiel des follow Status und des von checkItemsNearby() vorgenommenen Übergangs die folgende Implementierung an:

Mit dieser Version von follow() wechselt ein Soldat zu collectItem oder runAway, bevor überprüft wird, ob sich ein Feind in der Nähe befindet. Infolgedessen sammelt der Soldat einen Gegenstand (oder flieht vor ihm), selbst wenn sich Feinde in der Nähe befinden, die vom hunt Status gejagt werden sollten.

Hier ist eine weitere Implementierung:

Mit dieser Version von follow() wechselt ein Soldat erst dann zu collectItem oder runAway, wenn er feststellt, dass keine Feinde zu töten sind.

Die aktuelle Implementierung von follow(), hunt() und collectItem() leidet unter Prioritätsproblemen. Der Soldat wird versuchen, einen Gegenstand zu sammeln, auch wenn wichtigere Dinge zu tun sind. Um dies zu beheben, sind einige Anpassungen erforderlich.

In Bezug auf den follow Status kann der Code aktualisiert werden auf:

(follow() mit Prioritäten)

hunt status muss geändert werden in:

Schließlich muss der Status collectItem geändert werden, um Plünderungen abzubrechen, wenn sich ein Feind in der Nähe befindet:

Das Ergebnis all dieser Änderungen ist die Demo vom Anfang des Tutorials:

Squad-Muster implementiert mit stapelbasiertem FSM und Steering-Verhalten. Bewegen Sie den Mauszeiger, um den Anführer zu führen, und klicken Sie, um zu schießen.

Abschluss

In diesem Tutorial haben Sie gelernt, wie Sie ein Truppmuster codieren, bei dem eine Gruppe von Soldaten einem Anführer folgt, in der Nähe befindliche Feinde jagt und plündert. Die KI wird mithilfe eines stapelbasierten FSM in Kombination mit mehreren Steering-Verhalten implementiert.

Wie gezeigt, sind Finite-State-Maschinen und Steering-Verhalten eine leistungsstarke Kombination und passen hervorragend zusammen. Durch die Verteilung der Logik auf die FSM-Zustände kann dynamisch ausgewählt werden, welche Lenkkräfte auf einen Charakter wirken, wodurch komplexe KI-Muster erstellt werden können.

Kombinieren Sie das bereits bekannte Steering-Verhalten mit FSMs und erstellen Sie neue und herausragende Muster!

Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.