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

Erstellen Sie eine Hockeyspiel-KI mit Lenkverhalten: Angriff

by
Read Time:19 minsLanguages:
This post is part of a series called Create AI for a Hockey Game Using Steering Behaviors.
Create a Hockey Game AI Using Steering Behaviors: Foundation
Create a Hockey Game AI Using Steering Behaviors: Defense

German (Deutsch) translation by Alex Grigorovich (you can also view the original English article)

In diesem Tutorial codieren wir weiterhin künstliche Intelligenz für ein Hockeyspiel unter Verwendung von Steuerungsverhalten und endlichen Zustandsautomaten. In diesem Teil der Serie lernen Sie die KI kennen, die von Spieleinheiten benötigt wird, um einen Angriff zu koordinieren, bei dem es darum geht, den Puck abzufangen und zum Ziel des Gegners zu tragen.

Ein paar Worte zum Angriff

Die Koordination und Durchführung eines Angriffs in einem kooperativen Sportspiel ist eine sehr komplexe Aufgabe. In der realen Welt treffen Menschen, wenn sie ein Hockeyspiel spielen, mehrere Entscheidungen, die auf vielen Variablen beruhen.

Diese Entscheidungen beinhalten Berechnungen und das Verständnis dessen, was vor sich geht. Ein Mensch kann anhand der Aktionen eines anderen Gegners erkennen, warum sich ein Gegner bewegt, zum Beispiel "er bewegt sich, um in einer besseren strategischen Position zu sein". Es ist nicht trivial, dieses Verständnis auf einen Computer zu übertragen.

Wenn wir also versuchen, die KI so zu codieren, dass sie allen menschlichen Nuancen und Wahrnehmungen folgt, wird das Ergebnis ein riesiger und beängstigender Haufen Code sein. Darüber hinaus ist das Ergebnis möglicherweise nicht präzise oder leicht zu ändern.

Aus diesem Grund versucht unsere Angriffs-KI, das Ergebnis einer Gruppe von Menschen zu imitieren, nicht die menschliche Wahrnehmung selbst. Dieser Ansatz führt zu Annäherungen, aber der Code wird leichter zu verstehen und zu optimieren sein. Das Ergebnis ist gut genug für mehrere Anwendungsfälle.

Den Angriff mit Staaten organisieren

Wir werden den Angriffsprozess in kleinere Teile zerlegen, wobei jeder eine ganz bestimmte Aktion ausführt. Diese Teile sind die Zustände eines stapelbasierten endlichen Automaten. Wie zuvor erläutert, erzeugt jeder Zustand eine Lenkkraft, die den Athleten dazu bringt, sich entsprechend zu verhalten.

Die Orchestrierung dieser Zustände und die Bedingungen für den Wechsel zwischen ihnen werden den Angriff definieren. Das folgende Bild zeigt das komplette im Prozess verwendete FSM:

Eine stapelbasierte Finite-State-Maschine, die den Angriffsprozess darstellt.

Wie das Bild zeigt, basieren die Bedingungen für den Wechsel zwischen den Zuständen ausschließlich auf der Entfernung und dem Besitz des Pucks. Zum Beispiel hat das team has the puck oder der puck is too far away.

Der Angriffsprozess besteht aus vier Zuständen: idle, attack, stealPuck und pursuePuck. Der idle zustand wurde bereits im vorherigen Tutorial implementiert und ist der Ausgangspunkt des Prozesses. Von dort aus wechselt ein Athlet zum attack, wenn das Team den Puck hat, zum stealPuck, wenn das gegnerische Team den Puck hat, oder zum pursuePuck, wenn der Puck keinen Besitzer hat und nahe genug ist, um gesammelt zu werden.

Der attack-Stand repräsentiert eine offensive Bewegung. In diesem Zustand versucht der Athlet, der den Puck trägt (sogenannter leader), das Ziel des Gegners zu erreichen. Teamkollegen werden mitziehen und versuchen, die Aktion zu unterstützen.

Der stealPuck-Zustand repräsentiert etwas zwischen einer defensiven und einer offensiven Bewegung. In diesem Zustand konzentriert sich ein Athlet darauf, den Gegner mit dem Puck zu verfolgen. Ziel ist es, den Puck zurückzuerobern, damit das Team wieder angreifen kann.

Schließlich hat der pursuePuck-Zustand nichts mit Angriff oder Verteidigung zu tun; es wird die Athleten nur führen, wenn der Puck keinen Besitzer hat. In diesem Zustand versucht ein Athlet, den Puck, der sich frei auf dem Spielfeld bewegt, zu bekommen (zum Beispiel nachdem er von einem Schläger getroffen wurde).

Aktualisieren des Ruhezustands

Der zuvor implementierte idle zustand hatte keine Übergänge. Da dieser Zustand der Ausgangspunkt für die gesamte KI ist, aktualisieren wir ihn und machen ihn in die Lage, in andere Zustände zu wechseln.

Der idle zustand hat drei Übergänge:

Der Ruhezustand und seine Übergänge im FSM beschreiben den Angriffsprozess.

Wenn das Team des Athleten den Puck hat, sollte der idle aus dem Gehirn geknallt und der attack sollte vorangetrieben werden. Wenn das gegnerische Team den Puck hat, sollte idle durch stealPuck ersetzt werden. Der verbleibende Übergang findet statt, wenn niemand den Puck besitzt und er sich in der Nähe des Athleten befindet; In diesem Fall sollte pursuePuck in das Gehirn geschoben werden.

Die aktualisierte Version von idle ist wie folgt (alle anderen Zustände werden später implementiert):

Fahren wir mit der Implementierung der anderen Staaten fort.

Den Puck verfolgen

Nachdem der Athlet nun eine gewisse Wahrnehmung der Umgebung gewonnen hat und in der Lage ist, vom idle in jeden Zustand zu wechseln, konzentrieren wir uns darauf, den Puck zu verfolgen, wenn er keinen Besitzer hat.

Ein Athlet wechselt sofort nach Beginn des Spiels zum pursuePuck, da der Puck ohne Besitzer in der Mitte des Spielfelds platziert wird. Der pursuePuck-Zustand hat drei Übergänge:

Der pursuePuck-Zustand und seine Übergänge im FSM beschreiben den Angriffsprozess.

Der erste Übergang ist, dass puck is too far away und versucht zu simulieren, was in einem echten Spiel beim Jagen des Pucks passiert. Aus strategischen Gründen versucht normalerweise der Athlet, der dem Puck am nächsten ist, ihn zu fangen, während die anderen warten oder versuchen zu helfen.

Ohne bei weit entferntem Puck in den idle zu schalten, würde jeder KI-gesteuerte Athlet den Puck gleichzeitig verfolgen, auch wenn er sich von ihm entfernt befindet. Durch die Überprüfung der Entfernung zwischen dem Athleten und dem Puck löst sich pursuePuck selbst aus dem Gehirn und drückt im idle, wenn der Puck zu weit entfernt ist, was bedeutet, dass der Athlet einfach aufgegeben hat, den Puck zu verfolgen:

Wenn der Puck nah ist, muss der Athlet ihm nachgehen, was mit dem Suchverhalten leicht erreicht werden kann. Unter Verwendung der Position des Pucks als Suchziel verfolgt der Athlet den Puck anmutig und passt seine Flugbahn an, wenn sich der Puck bewegt:

Die verbleibenden zwei Übergänge im pursuePuck-Zustand, das team has the puck und der opponent has the puck, beziehen sich darauf, dass der Puck während des Verfolger-Prozesses gefangen wurde. Wenn jemand den Puck fängt, muss der Athlet den pursuePuck-Zustand knacken und einen neuen ins Gehirn schieben.

Der zu pushende Zustand hängt vom Besitz des Pucks ab. Wenn der Aufruf von doesMyTeamHaveThePuck() true zurückgibt, bedeutet dies, dass ein Teamkollege den Puck bekommen hat, sodass der Athlet den attack forcieren muss, was bedeutet, dass es an der Zeit ist, die Verfolgung des Pucks einzustellen und sich auf das Ziel des Gegners zuzubewegen. Wenn ein Gegner den Puck bekommen hat, muss der Athlet den stealPuck drücken, wodurch das Team versucht, den Puck zurückzugewinnen.

Als kleine Verbesserung sollten Athleten während des pursuePuck-Zustands nicht zu nahe beieinander bleiben, da eine "überfüllte" Verfolgungsbewegung unnatürlich ist. Das Hinzufügen einer Trennung zur Lenkungskraft des Staates (Zeile 6 im obigen Code) stellt sicher, dass die Athleten einen Mindestabstand zwischen ihnen einhalten.

Das Ergebnis ist ein Team, das den Puck verfolgen kann. Zu Testzwecken wird in dieser Demo der Puck alle paar Sekunden in der Mitte der Eisbahn platziert, damit sich die Athleten kontinuierlich bewegen:

Angriff mit dem Puck

Nach Erhalt des Pucks müssen sich ein Athlet und sein Team auf das gegnerische Tor zubewegen, um ein Tor zu erzielen. Das ist der Zweck des attack-Zustands:

Der Angriffszustand und seine Übergänge im FSM, die den Angriffsprozess beschreiben.

Der attack-Zustand hat nur zwei Übergänge: opponent has the puck und der puck has no owner. Da der Zustand ausschließlich dazu dient, die Athleten zum gegnerischen Tor zu bewegen, macht es keinen Sinn, im Angriff zu bleiben, wenn der Puck nicht mehr im Besitz der Mannschaft ist.

Bezüglich der Bewegung zum gegnerischen Tor: Der Athlet, der den Puck trägt (Anführer) und die ihm helfenden Mitspieler sollten sich anders verhalten. Der Anführer muss das Ziel des Gegners erreichen und die Teamkollegen sollten ihm auf dem Weg helfen.

Dies kann implementiert werden, indem überprüft wird, ob der Athlet, der den Code ausführt, den Puck hat:

Wenn amIThePuckOwner() true zurückgibt (Zeile 10), hat der Athlet, der den Code ausführt, den Puck. In diesem Fall wird er nur die gegnerische Torposition suchen. Das ist so ziemlich die gleiche Logik, die verwendet wird, um den Puck im pursuePuck-Zustand zu verfolgen.

Wenn amIThePuckOwner() false zurückgibt, hat der Athlet keinen Puck, daher muss er dem Anführer helfen. Dem Leiter zu helfen ist eine komplizierte Aufgabe, daher werden wir sie vereinfachen. Ein Athlet wird dem Führenden helfen, indem er einfach eine Position vor ihm sucht:

Teamkollegen, die den Führer unterstützen.

Wenn sich der Anführer bewegt, wird er von seinen Teamkollegen umgeben, die dem ahead Punkt folgen. Dies gibt dem Anführer einige Optionen, an die er den Puck weitergeben kann, wenn es Probleme gibt. Wie in einem echten Spiel sollten auch die umliegenden Teamkollegen dem Führenden aus dem Weg gehen.

Dieses Unterstützungsmuster kann erreicht werden, indem eine leicht modifizierte Version des Führungsverhaltens hinzugefügt wird (Zeile 18). Der einzige Unterschied besteht darin, dass die Athleten einem Punkt vor dem Anführer folgen, anstatt einem Punkt hinter ihm, wie er ursprünglich in diesem Verhalten implementiert wurde.

Auch Athleten, die den Führenden unterstützen, sollten untereinander einen Mindestabstand einhalten. Dies wird durch Hinzufügen einer Trennkraft implementiert (Zeile 19).

Das Ergebnis ist eine Mannschaft, die sich auf das gegnerische Tor zubewegen kann, ohne sich zu drängen und eine unterstützte Angriffsbewegung zu simulieren:

Verbesserung der Angriffsunterstützung

Die aktuelle Implementierung des attack-Zustands ist für einige Situationen gut genug, hat jedoch einen Fehler. Wenn jemand den Puck fängt, wird er zum Anführer und wird sofort von Mitspielern verfolgt.

Was passiert, wenn sich der Anführer seinem eigenen Ziel nähert, wenn er den Puck fängt? Schauen Sie sich die obige Demo genauer an und bemerken Sie das unnatürliche Muster, wenn Teamkollegen dem Anführer folgen.

Wenn der Anführer den Puck fängt, braucht das Suchverhalten einige Zeit, um die Flugbahn des Anführers zu korrigieren und ihn effektiv zum gegnerischen Tor zu bewegen. Selbst wenn der Anführer "manövriert", versuchen Teamkollegen, seinen ahead zu suchen, was bedeutet, dass sie sich ihrem eigenen Ziel (oder dem Ort, auf den der Anführer starrt) nähern.

Wenn der Anführer endlich in Position ist und bereit ist, sich auf das gegnerische Tor zuzubewegen, werden die Teamkollegen "manövrieren", um dem Anführer zu folgen. Der Anführer bewegt sich dann ohne Unterstützung der Teamkollegen, solange die anderen ihre Flugbahnen anpassen.

Dieser Fehler kann behoben werden, indem überprüft wird, ob der Teamkollege dem Anführer voraus ist, wenn das Team den Puck zurückerlangt. Die Bedingung "vorne" bedeutet hier "näher am gegnerischen Tor":

Wenn der Leader (der der Puckbesitzer ist) dem Athleten voraus ist, der den Code ausführt, dann sollte der Athlet dem Leader folgen, genau wie er es zuvor getan hat (Zeilen 27 und 28). Wenn der Führende hinter ihm ist, sollte der Athlet seine aktuelle Position halten und einen Mindestabstand zwischen den anderen einhalten (Linie 33).

Das Ergebnis ist etwas überzeugender als die erste attack-Implementierung:

Tipp: Durch Optimieren der Entfernungsberechnungen und Vergleiche in der isAheadOfMe()-Methode können Sie die Art und Weise ändern, in der Athleten ihre aktuellen Positionen halten.

Den Puck stehlen

Der letzte Zustand im Angriffsprozess ist der stealPuck, der aktiv wird, wenn das gegnerische Team den Puck hat. Der Hauptzweck des stealPuck-Zustands besteht darin, dem Gegner, der ihn trägt, den Puck zu stehlen, damit das Team wieder angreifen kann:

Der stealPuck-Zustand und seine Übergänge im FSM beschreiben den Angriffsprozess.

Da die Idee hinter diesem Zustand darin besteht, dem Gegner den Puck zu stehlen, wird sich stealPuck selbst aus dem Gehirn platzen und den richtigen Zustand in den richtigen Zustand bringen, wenn der Puck vom Team zurückgeholt wird oder frei wird (dh er hat keinen Besitzer). Umgang mit der neuen Situation:

Wenn der Puck einen Besitzer hat und dieser zum gegnerischen Team gehört, muss der Athlet den gegnerischen Anführer verfolgen und versuchen, den Puck zu stehlen. Um den Anführer des Gegners zu verfolgen, muss ein Athlet vorhersagen, wo er in naher Zukunft sein wird, damit er in seiner Flugbahn abgefangen werden kann. Das ist etwas anderes, als nur den gegnerischen Anführer zu suchen.

Glücklicherweise kann dies mit dem Verfolger-Verhalten leicht erreicht werden (Zeile 19). Durch den Einsatz einer Verfolgungskraft im stealPuck-Zustand versuchen die Athleten, den Anführer des Gegners abzufangen, anstatt ihm nur zu folgen:

Verhindern einer überfüllten Diebstahlbewegung

Die aktuelle Implementierung von stealPuck funktioniert, aber in einem echten Spiel nähern sich nur ein oder zwei Athleten dem gegnerischen Anführer, um den Puck zu stehlen. Der Rest des Teams bleibt in den umliegenden Gebieten und versucht zu helfen, was ein überfülltes Diebstahlmuster verhindert.

Es kann behoben werden, indem vor der Verfolgung des gegnerischen Führers eine Distanzprüfung (Zeile 17) hinzugefügt wird:

Anstatt den Anführer des Gegners blindlings zu verfolgen, prüft ein Athlet, ob der Abstand zwischen ihm und dem Anführer des Gegners kleiner als beispielsweise 150 ist. Wenn das true, erfolgt die Verfolgung normal, aber wenn der Abstand größer als 150 ist, bedeutet dies, dass die Athlet ist zu weit vom gegnerischen Anführer entfernt.

In diesem Fall macht es keinen Sinn, weiterhin zu versuchen, den Puck zu stehlen, da er zu weit entfernt ist und wahrscheinlich bereits Teamkollegen vorhanden sind, die versuchen, dasselbe zu tun. Die beste Option ist, den stealPuck aus dem Gehirn zu werfen und den defense-Zustand zu pushen (was im nächsten Tutorial erklärt wird). Vorerst wird ein Athlet nur seine aktuelle Position halten, wenn der gegnerische Anführer zu weit entfernt ist.

Das Ergebnis ist ein überzeugenderes und natürlicheres Stealing-Muster (kein Crowding):

Gegner beim Angriff vermeiden

Es gibt noch einen letzten Trick, den die Athleten lernen müssen, um effektiv angreifen zu können. Im Moment bewegen sie sich auf das gegnerische Tor zu, ohne die Gegner auf dem Weg zu berücksichtigen. Ein Gegner muss als Bedrohung angesehen werden und sollte vermieden werden.

Mithilfe des Kollisionsvermeidungsverhaltens können Athleten Gegnern ausweichen, während sie sich bewegen:

Kollisionsvermeidungsverhalten, das verwendet wird, um Gegnern auszuweichen.

Gegner werden als kreisförmige Hindernisse gesehen. Aufgrund der dynamischen Natur des Lenkverhaltens, das in jeder Spielschleife aktualisiert wird, funktioniert das Ausweichmuster elegant und reibungslos für sich bewegende Hindernisse (was hier der Fall ist).

Um die Athleten dazu zu bringen, Gegnern(Hindernissen) auszuweichen, muss dem Angriffszustand (Zeile 14) eine einzelne Zeile hinzugefügt werden:

Diese Linie fügt dem Athleten eine Kollisionsvermeidungskraft hinzu, die mit den bereits vorhandenen Kräften kombiniert wird. Infolgedessen vermeidet der Athlet Hindernisse und sucht gleichzeitig das Ziel des Gegners.

Unten ist eine Demonstration eines Athleten, der den attack-Zustand durchführt. Gegner sind unbeweglich, um das Kollisionsvermeidungsverhalten hervorzuheben:

Abschluss

In diesem Tutorial wurde die Implementierung des Angriffsmusters erklärt, mit dem die Athleten den Puck stehlen und zum gegnerischen Ziel tragen. Durch eine Kombination von Lenkverhalten sind Sportler nun in der Lage, komplexe Bewegungsmuster auszuführen, wie zum Beispiel einem Anführer zu folgen oder den Gegner mit dem Puck zu verfolgen.

Wie bereits erwähnt, zielt die Angriffsimplementierung darauf ab, zu simulieren, was Menschen tun, sodass das Ergebnis eine Annäherung an ein reales Spiel ist. Indem Sie die Zustände, aus denen sich der Angriff zusammensetzt, individuell anpassen, können Sie eine bessere Simulation erstellen oder eine, die Ihren Anforderungen entspricht.

Im nächsten Tutorial lernst du, wie man Athleten dazu bringt, sich zu verteidigen. Die KI wird vollständig funktionstüchtig, kann angreifen und verteidigen, was zu einem Spiel mit 100% KI-kontrollierten Teams führt, die gegeneinander spielen.

Verweise

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.