Komponenten- / entitätsbasiertes Design + Verhaltensbäume => Wie integriere ich?

9

Für mein aktuelles Projekt habe ich ein komponenten- / entitätsbasiertes System implementiert , das im Wesentlichen den meisten Best Practices in diesem eher undefinierten Bereich folgt .

Also habe ich (leicht erweiterte) Entitäten erhalten , die im Grunde eine intID, einen für Menschen lesbaren Namen, eine std::mapder Komponenten und einen long"Typindikator" sind, der verwendet wird, um anzuzeigen, welche Komponenten vorhanden sind (ich habe eine Zweierpotenz enumfür alle Komponenten Typen und wann immer eine Komponente zur Entität hinzugefügt wird, ändere ich diese Länge automatisch über bitweise Operationen (vergleiche diese Antwort ).

Dann gibt es die Komponenten , auch ziemlich einfach: intID enumals Komponententyp, übergeordneter Entitätszeiger und eine std::mapaller Eigenschaften, die diese Komponente enthält.

Zuletzt einige Systeme / Manager , die die eigentliche Logikverarbeitung übernehmen. Sie prüfen zunächst, ob die aktuell verarbeitete Entität einen übereinstimmenden long"Typindikator" hat = alle für dieses System erforderlichen Komponenten sind vorhanden. Bei Bedarf greift es dann auf einige Eigenschaften zu und ruft entweder einige Funktionen in der jeweiligen Komponente direkt auf oder sendet einige Nachrichten (über einen Nachrichten-Dispatcher).

Fazit: Bis hier ein eher standardmäßiges ereignisgesteuertes komponenten- / entitätsbasiertes System in Kombination mit einem datengesteuerten Ansatz (vergleiche, Komponenten haben keine fest codierten Datenvariablen, sondern eine generische Zuordnung als (einige) Komponenten / Archetypen von Komponenten werden später aus Dateien mit der Option gelesen, zusätzliche Daten hinzuzufügen, die nicht Teil des eigentlichen Komponentencodes sind.

Jetzt möchte ich auch Verhaltensbäume (basierend auf AiGameDev BTSK ) in dieses Projekt einführen , bin mir aber nicht sicher, ob und wie sie mit den bereits vorhandenen Komponenten verknüpft werden sollen oder wie diese Designs im Allgemeinen integriert werden sollen.

Einige verwandte Ideen / Punkte / Fragen kommen in den Sinn:

  1. Meine BTs werden (wieder) aus Dateien gelesen. Es fällt mir derzeit schwer zu sehen, wie ich die Verbindung zwischen einem BT Actionin diesem Baum und der tatsächlichen Codierung in meiner Anwendung am besten herstellen kann . Sollte ich eine Art Map zwischen den in den BT-Dateien verwendeten Aktionsnamen und einem Funktionszeiger auf die tatsächliche Logikimplementierung erstellen? Was ist der übliche Ansatz, um das zu lösen?

  2. Ich gehe davon aus, dass ich BTs für alle meine verschiedenen EntityTypen erstellen muss (also für jede spiellogik- / AI-relevante Kombination von Komponenten, wie durch meinen mehrfach erwähnten langen "Typindikator" angezeigt). Infolgedessen ist es nicht sinnvoll, die BT ActionImplementierungen in die Komponenten einzufügen, da höchstwahrscheinlich viele Komponenten pro Aktion beteiligt sind, oder?

  3. Sollte sich die BT ActionLogik also in einem / mehreren separaten Systemen befinden (auf deren Methoden die Karte von Idee Nr. 1 zeigt)? Das System würde dann anhand meines long"Typindikators" prüfen, ob das, Entityfür das das BT derzeit geprüft wird und das angewiesen wurde, eine bestimmte Aktion auszuführen (= Methode im System), dies tatsächlich darf (= die erforderlichen Komponenten hat). Andernfalls würde nichts passieren, da beispielsweise der BT-Ersteller eine bestimmte Situation übersehen hat, in der eine erforderliche Komponente zur Laufzeit möglicherweise nicht mehr an die Entität angehängt ist.

Fragen:

  • Gibt es bewährte Konzepte für diese Art der Integration?
  • Wie sehen Sie meine 3 Punkte oben?
  • Gibt es noch andere Dinge, die mir in den Sinn kommen, auch in Bezug auf mein komponenten- / entitätsbasiertes Design im Allgemeinen?
Philip Allgaier
quelle
Zu Punkt 1: Verhaltensbäume sind nichts anderes als ein visuelles DSL, das hauptsächlich zum Erstellen von Charakterverhalten verwendet wird. Eine BehaviorTree-Komponente sollte nicht mehr oder weniger tun als eine Skriptkomponente. Zu Punkt 3: Was ist der Grund für die Verwendung einer Karte über regulären Feldern?
Eric
# 1: Wofür steht "DSL" in diesem Zusammenhang? # 3: Entschuldigung, aber ich kann dir in diesem Fall nicht folgen. Möchtest du bitte erklären, was du meinst?
Philip Allgaier
1
wahrscheinlich domänenspezifische Sprache, dh. Eine benutzerdefinierte Syntax, um mit einem ganz bestimmten Problem zu arbeiten.
Patrick Hughes
Patrick hat Recht, obwohl eine Semantik ebenfalls Teil davon ist und "sehr" aus dieser Definition gestrichen werden kann. - Zu 3: Ich entschuldige mich, es sollte lauten: "Was ist der Grund für die Verwendung einer Karte über regulären Feldern in Komponenten ?"
Eric
Zu 3: Ich möchte die Möglichkeit haben, später zusätzliche Eigenschaften außerhalb des C ++ - Codes dynamisch anzugeben (Schlagwort: datengesteuert). Der Einfachheit halber habe ich (zumindest für den Moment) alle Eigenschaften in dieses generische Framework eingefügt (unter Verwendung von Maps), auch diejenigen, die im Code fixiert sind und daher echte C ++ - Felder sein könnten. Möglicherweise müssen Sie das zu einem späteren Zeitpunkt noch einmal überprüfen, wenn es zu einem Leistungsproblem wird ...
Philip Allgaier

Antworten:

2

Es fällt mir derzeit schwer zu sehen, wie ich die Verbindung zwischen einer BT-Aktion in diesem Baum und der tatsächlichen Codierung in meiner Anwendung am besten herstellen kann. Sollte ich eine Art Map zwischen den in den BT-Dateien verwendeten Aktionsnamen und einem Funktionszeiger auf die tatsächliche Logikimplementierung erstellen? Was ist der übliche Ansatz, um das zu lösen?

Vergessen Sie Funktionszeiger und denken Sie an Objekte. Jeder Knoten im Verhaltensbaum (BT ab diesem Zeitpunkt) würde idealerweise einem Objekt in Ihrem Code entsprechen. Diese Objekte verfügen über eine Standardschnittstelle, über die Sie sie als Baum anordnen und durchlaufen können. Eine Reihe von Funktionszeigern ist für das Verhalten in Ordnung, erfasst jedoch überhaupt nicht die Struktur Ihres Baums.

Daher ist es nicht sinnvoll, die BT-Aktionsimplementierungen in die Komponenten einzufügen, da höchstwahrscheinlich viele Komponenten pro Aktion beteiligt sind, oder?

Ich würde erwarten, dass Entitäten eine einzige BehaviorTree-Komponente haben, in der die relevanten Daten für das BT dieser Entität gespeichert sind. Die Ausführung des BT erfolgt entweder durch die BT-Komponente oder das BT-Subsystem, je nachdem, wie Sie mit Komponenten in Ihrem System umgehen. Wie bei so ziemlich allem, was Komponenten verwendet, müssen sie sich auf andere Komponenten beziehen, um die Arbeit zu erledigen, aber diese anderen Komponenten müssen nichts über BTs wissen.

Die verschiedenen verfügbaren Aktionen würden auf der einfachsten Ebene in die verschiedenen BT-Knotenobjekte codiert. Sie sollten in der Lage sein, die relevante Entität zum Handeln zu bewegen, indem sie die Komponenten nach Bedarf manipulieren, z. Zugriff auf die Bewegungskomponente zum Bewegen.

Kylotan
quelle
Absatz 1: Ja, das BT selbst wird ein Objekt sein (wie gesagt, wie die Version von AiGameDev). Ich habe nur über Funktoren für die Aktionen selbst nachgedacht, aber Ihr Absatz 2 hat das geändert. Aus irgendeinem Grund ist mir dieser wirklich einfache Ansatz nie in den Sinn gekommen (Entity hat eine eigene BT-Mitgliedsinstanz). Wahrscheinlich aufgrund der neuen Komponentensache habe ich nicht mehr klar und einfach gedacht, also habe ich nach einer Möglichkeit gesucht, Komponenten mit dem BT-Material zu mischen, aber das wird in der Tat nicht benötigt.
Philip Allgaier
Die Hauptsache, bei der ich mich zuvor verlaufen habe, war, wie ich die Aktion mit der Entität verbinden kann. Jetzt ist klar: Die Aktionen wissen über ihren Baum, welche Entität die Entität kennt, zu der sie gehört.
Philip Allgaier
@Philip Allgaier Ich bin neugierig, wie bist du zum BT-Knoten gekommen? Haben Sie es als 1 Verhaltensknoten = 1 Entität erstellt (das wären viele Entitäten pro 1 Spielobjekt) oder einen Knoten als normale Klasse (nicht ECS-bezogen) erstellt oder andere Ansätze verwendet? Danken!
cppBeginner