Godot-Verhaltensbaum
Eine GDScript-Implementierung eines Verhaltensbaums für Spiel-KI, basierend auf nativen Godot-Knoten und unter Verwendung des integrierten Szenenbaum-Editors.
C#-VERSION -> https://github.com/MadFlyFish/godot-behavior-tree-csharp
INSTALLATION
- Kopieren Sie den Ordner „addons“ in das Hauptverzeichnis Ihres Projekts.
- Aktivieren Sie das Plugin in den Projekteinstellungen und starten Sie dann Godot neu, da es sonst die neuen Klassen nicht erkennt (das ist ein Fehler der Engine).
- Optional können Sie den Ordner bt_example auch in das Hauptverzeichnis Ihres Projekts ziehen.
- Um zu sehen, wie das Beispiel funktioniert, führen Sie die Szene „agent.tscn“ aus. Die Szene ex_behavior_tree.tscn ist ein Beispiel dafür, wie der Baum aufgebaut ist.
ANWEISUNGEN:
- Klicken Sie auf das Symbol zur Knotenerstellung. Es sollten neue Knoten verfügbar sein (falls nicht, starten Sie Godot neu). Sie müssen einen BehaviourTree als Wurzelknoten verwenden, der nur ein einziges untergeordnetes Element haben sollte. Bei diesem untergeordneten Element kann es sich um einen beliebigen Knoten unter der Kategorie „BTNode“ handeln, die alle von der Klasse „BTNode“ erben.
- Nachdem Sie einen Verhaltensbaum erstellt haben, müssen Sie angeben, wer der Eigentümer der KI (der Agent) ist und welches Blackboard verwendet wird. Tafeln können überall platziert werden (vorausgesetzt, sie befinden sich außerhalb des Baums) und sogar von mehreren Bäumen gemeinsam genutzt werden. Das System ist flexibel genug, um Ihnen die Entscheidung zu ermöglichen, wie und wann Sie Ihre Blackboard-Daten aktualisieren möchten. Sie können beispielsweise einen einfachen Knoten mit einem Skript erstellen, das die Aktualisierung des Blackboards übernimmt, z. mit Signalrückrufen oder sogar in process(). Sie können dies auch von einem anderen Ort aus tun, sogar aus dem Inneren des Baums heraus. Stellen Sie jedoch sicher, dass Sie die Dinge so gestalten, dass Sie sie verwalten und im Auge behalten können.
- Ein Verhaltensbaum führt jedes seiner untergeordneten Elemente aus, die einen Erfolgs- oder Misserfolgsstatus zurückgeben. Es werden nur die Zweige ausgeführt, die auf einen erfolgreichen Knoten folgen. Ein BTNode muss entweder Erfolg oder Misserfolg zurückgeben und kann die Ausführung nur mit einem yield()-Aufruf unterbrechen. Danach bleibt er im laufenden Zustand, bis die Ausführung abgeschlossen ist. Wenn sich ein BTNode im Ausführungsstatus befindet, unterbricht der Baum die Ausführung schrittweise (mit der einzigen Ausnahme BTParallel ), bis alle untergeordneten Knoten die Ausführung abgeschlossen haben. Dies dient Optimierungszwecken.
- Der Fluss des Baums wird durch die sogenannten zusammengesetzten Knoten definiert: BTSequence, BTSelector, BTRandomSelector, BTRandomSequence, BTParallel, die alle von BTComposite erben. Eine Sequenz ist erfolgreich, wenn alle Kinder erfolgreich sind, während sie fehlschlägt, wenn eines der Kinder fehlschlägt. Der Selektor ist das logische Gegenteil: Er ist erfolgreich, wenn ein Kind erfolgreich ist, und schlägt fehl, wenn alle Kinder fehlschlagen. Eine Parallele führt alle untergeordneten Elemente aus und ist unabhängig davon immer erfolgreich, OHNE darauf zu warten, dass die untergeordneten Elemente die Ausführung abschließen. Der Basisverbundknoten führt alle untergeordneten Knoten aus und ist immer erfolgreich, wartet aber auch auf den Abschluss der Ausführung.
- Die Aktionen Ihres KI-Verhaltens werden in BTLeaf-Knoten ausgeführt. Fügen Sie ein BTLeaf hinzu und führen Sie dann „Skript erweitern“ aus. Jetzt können Sie in diesem Skript Ihr eigenes Verhalten definieren, indem Sie die Methode _ tick() überschreiben. Ihre Aktionen werden hier angezeigt. Lesen Sie unbedingt die Kommentare im Basisskript, um die Best Practices zu erfahren. Denken Sie auch daran, dass BTLeaf keine Kinder haben sollte.
- BTDecorator wird verwendet, um die Ausführung eines untergeordneten Knotens anzupassen. Sie können nur EIN Kind haben.
- BTCditional ist der häufigste Dekorateurtyp. Fügen Sie ein BTConditional hinzu, erweitern Sie das Skript und überschreiben Sie dann die Methode _ pre_tick(), um die Bedingungen zu definieren, unter denen das untergeordnete Element ausgeführt wird. Lesen Sie unbedingt den Kommentar, denn dort finden Sie ein nützliches Beispiel.
- BTGuards sind Dekoratoren, mit denen Zweige vorübergehend gesperrt werden können. Optional können Sie einen Entsperrer zuweisen, der die angegebene Sperrzeit außer Kraft setzt. Es besteht auch die Möglichkeit, einen Spind zuzuweisen. BTGuards können Ihr Verhalten sehr vielfältig und reaktiv gestalten und optimieren, da sie unnötige Verzweigungen und Wiederholungen vermeiden.
- Mit anderen Dekoratoren können Sie die Ausführung in einer Schleife ausführen, das Ergebnis eines Ticks umkehren usw. Sie können viel tun, indem Sie die Ausführung durch Dekorateure anpassen.
- Eine gute Vorgehensweise besteht darin, die bereitgestellten Knoten zu verwenden und dem Entwurfsmuster des Verhaltensbaums zu folgen. Da es sich jedoch um eine rein codebasierte Implementierung ohne visuellen Editor handelt, haben Sie viel Kontrolle über das Design und somit eine Fehlerquote. Hierbei handelt es sich lediglich um nützliche Skripte, die einigen „guten Praktiken“ folgen, aber nicht an diese gebunden sind, wenn nicht ein paar Grundregeln gelten. Es liegt an Ihnen, zu entscheiden, wie Sie Ihren Verhaltensbaum entwerfen. Bedenken Sie jedoch, dass Sie bei Missbrauch nicht von der Leistungsfähigkeit des Verhaltensbaummusters profitieren. (Sie könnten zum Beispiel sogar den Basis-BTNode für alles verwenden und ihn jedes Mal erweitern, obwohl das ein Chaos wäre)
- Sie könnten einen riesigen Verhaltensbaum haben, aber die beste Vorgehensweise besteht darin, der Komponentenphilosophie von Godot zu folgen und mehrere kleinere Verhaltensbäume für jede Komponente Ihrer Szene zu erstellen. Zum Beispiel ein Baum für Ihren Bewegungscontroller, ein Baum für Ihren Waffencontroller, ein Baum für Ihre Pathfinder-Komponente usw. Ein Verhaltensbaum kann nur eine Tafel haben, aber dieselbe Tafel kann von vielen Bäumen verwendet werden, also ist dies der Fall Besonders praktisch, wenn Sie mehrere Bäume haben möchten, ohne gleichzeitig mehrere Tafeln zu erstellen. Persönlich habe ich die Tafel als entkoppelte Komponente, weil ich Trupps aus Feinden erstellen wollte, die dieselben Daten teilen, sich aber unabhängig verhalten, also ist dies ein Anwendungsfall dafür. Darüber hinaus habe ich normalerweise mehrere Komponenten in meinen Schauspielern und möchte dieselbe Datenbank für verschiedene Bäume verwenden.