Projektowanie oparte na komponentach / jednostkach + Drzewa zachowań => jak zintegrować?

9

W ramach mojego obecnego projektu wdrożyłem system oparty na komponentach / jednostkach , zasadniczo przestrzegając większości najlepszych praktyk w tym raczej nieokreślonym obszarze .

Mam więc (nieco rozszerzone) byty , które są w zasadzie intidentyfikatorem, czytelną dla człowieka nazwą, std::mapskładników i long„wskaźnikiem typu”, który służy do pokazania, które składniki są obecne (mam moc dwóch enumdla wszystkich składników typy i za każdym razem, gdy komponent jest dodawany do Entity, automatycznie zmieniam tę długość za pomocą operacji bitowych, porównuję tę odpowiedź ).

Są jeszcze Komponenty , również dość proste: intID, enumjako typ komponentu, wskaźnik encji nadrzędnej i std::mapwszystkie właściwości, które posiada ten komponent.

Wreszcie niektóre systemy / menedżery, które obsługują faktyczne przetwarzanie logiki. Najpierw sprawdzają, czy aktualnie przetwarzana jednostka ma pasujący long„wskaźnik typu” = obecne są wszystkie niezbędne komponenty dla tego systemu. W razie potrzeby uzyskuje dostęp do niektórych właściwości i albo bezpośrednio wywołuje niektóre funkcje w odpowiednim składniku, albo wysyła niektóre wiadomości (za pośrednictwem programu rozsyłającego wiadomości).

Konkluzja: Do tej pory raczej standardowy system oparty na zdarzeniach oparty na komponentach / jednostkach w połączeniu z podejściem opartym na danych (porównaj, komponenty nie mają zakodowanych na stałe zmiennych danych, ale zamiast tego ogólną mapę, jako (niektóre) komponenty / archetypy komponentów zostaną później odczytane z plików z opcją dodania dodatkowych danych, które nie są częścią rzeczywistego kodu komponentu.

Teraz chciałbym również wprowadzić drzewa zachowań (oparte na AiGameDev BTSK ) do tego projektu, ale nie jestem pewien, czy i jak powinny one być powiązane z już istniejącymi komponentami lub jak ogólnie zintegrować te projekty.

Przychodzi mi na myśl kilka powiązanych pomysłów / punktów / pytań:

  1. Moje BT zostaną odczytane z plików (ponownie). Obecnie trudno mi się przekonać, jak najlepiej wykonać połączenie między BT Actiondrzewem w tym drzewie a rzeczywistym kodowaniem w mojej aplikacji. Czy powinienem stworzyć mapę między nazwami akcji użytymi w plikach BT a wskaźnikiem funkcji do rzeczywistej implementacji logiki? Jakie jest typowe podejście do rozwiązania tego problemu?

  2. Zakładam, że będę musiał stworzyć BT dla wszystkich moich różnych Entitytypów (więc dla każdej kombinacji elementów związanych z logiką gry / AI, jak wskazuje mój wielokrotnie wspomniany długi „wskaźnik typu”). W związku z tym nie ma sensu umieszczanie BT Actionimplementacji w komponentach, ponieważ najprawdopodobniej w akcję będzie zaangażowanych wiele komponentów, prawda?

  3. Czy więc BT Actionlogika powinna znajdować się w / osobnych systemach (do których metod wskazuje mapa od pomysłu nr 1)? Następnie system sprawdzałby według mojego long„wskaźnika typu”, czy ten, Entitydla którego BT jest aktualnie sprawdzany i który otrzymał polecenie wykonania określonej akcji (= metoda w systemie), jest w rzeczywistości dozwolony (= ma niezbędne komponenty). Ale jeśli nie (ponieważ na przykład twórca BT przeoczył określoną sytuację, w której niezbędny komponent może nie być dołączony do encji w czasie wykonywania), nic by się nie wydarzyło.

Pytania:

  • Czy istnieją sprawdzone koncepcje tego rodzaju integracji?
  • Co sądzisz o moich 3 punktach powyżej?
  • Jakieś inne rzeczy, które przychodzą na myśl, również w odniesieniu do mojego projektu opartego na komponentach / elementach w ogóle?
Philip Allgaier
źródło
Punkt 1: Drzewa zachowań to nic innego jak wizualna DSL używana głównie do tworzenia zachowań postaci. Składnik BehaviorTree nie powinien robić nic więcej ani mniej niż składnik Skrypt. Do punktu 3: Jaki jest powód używania mapy na zwykłych polach?
Eric
# 1: Co oznacza skrót „DSL” w tym kontekście? # 3: Przepraszam, ale nie mogę cię śledzić w tej sprawie. Chcesz wyjaśnić, proszę, co masz na myśli?
Philip Allgaier,
1
prawdopodobnie język specyficzny dla domeny, tj. niestandardowa składnia do pracy z bardzo specyficznym problemem.
Patrick Hughes,
Patrick ma rację, chociaż semantyka również jest jego częścią i „bardzo” może zostać usunięte z tej definicji. - Re 3: Przepraszam, powinien brzmieć: „Jaki jest powód używania mapy nad zwykłymi polami w komponentach ?”
Eric
Re 3: Chcę mieć możliwość późniejszego dynamicznego określenia dodatkowych właściwości poza kodem C ++ (modne hasło: sterowane danymi). Dla uproszczenia umieściłem (przynajmniej na razie) wszystkie właściwości w tym ogólnym środowisku (używając map), nawet te, które są poprawione w kodzie, a zatem mogą być prawdziwymi polami C ++. Może muszę to powtórzyć w późniejszym momencie, jeśli stanie się to problemem z wydajnością ...
Philip Allgaier

Odpowiedzi:

2

Obecnie trudno mi się przekonać, jak najlepiej wykonać połączenie BT Action w tym drzewie z faktycznym kodowaniem w mojej aplikacji. Czy powinienem stworzyć mapę między nazwami akcji użytymi w plikach BT a wskaźnikiem funkcji do rzeczywistej implementacji logiki? Jakie jest typowe podejście do rozwiązania tego problemu?

Zapomnij o wskaźnikach funkcji i pomyśl o obiektach. Każdy węzeł w drzewie zachowań (BT od tego momentu) idealnie odpowiadałby jednemu obiektowi w kodzie. Obiekty te będą miały standardowy interfejs pozwalający na ułożenie ich jako drzewa i przechodzenie przez nie. Zestaw wskaźników funkcji jest odpowiedni dla zachowania, ale w ogóle nie odzwierciedla struktury twojego drzewa.

W związku z tym nie ma sensu umieszczanie implementacji BT Action w komponentach, ponieważ najprawdopodobniej w akcję będzie zaangażowanych wiele komponentów, prawda?

Oczekiwałbym, że podmioty będą miały jeden składnik BehaviorTree, który przechowuje odpowiednie dane dla BT tego podmiotu. Wykonanie BT jest wykonywane przez Komponent BT lub Podsystem BT w zależności od sposobu obsługi komponentów w systemie. Podobnie jak w przypadku prawie wszystkich komponentów, będą musieli odwoływać się do innych komponentów, aby wykonać zadanie, ale te inne komponenty nie będą musiały nic wiedzieć o BT.

Różne dostępne działania byłyby, na najprostszym poziomie, zakodowane w różnych obiektach węzła BT. Powinny one być w stanie zmusić odpowiedni podmiot do działania poprzez manipulowanie komponentami w razie potrzeby, np. dostęp do komponentu ruchu w celu przeniesienia.

Kylotan
źródło
Akapit 1: Tak, sam BT będzie obiektem (jak powiedziałem, podobnie jak wersja AiGameDev). Myślałem tylko o funktorach dla samych działań, ale twój akapit # 2 to zmienił. Z jakiegoś powodu to naprawdę proste podejście nigdy nie przyszło mi do głowy (jednostka ma własną instancję członka BT). Prawdopodobnie z powodu zupełnie nowej rzeczy związanej z komponentami nie myślałem już o prostocie i prostocie, więc szukałem sposobu mieszania komponentów z elementami BT, ale tak naprawdę nie jest to potrzebne.
Philip Allgaier,
Najważniejszą rzeczą, na której wcześniej się zagubiłem, było połączenie akcji z bytem. Teraz jest jasne: akcje wiedzą, który byt poprzez swoje drzewo, który w zamian zna byt, do którego należy.
Philip Allgaier,
@Philip Allgaier Jestem ciekawy, jak udało ci się stworzyć węzeł BT? Czy stworzyłeś go jako 1 węzeł behawioralny = 1 encja (byłoby to wiele jednostek na 1 obiekt gry), czy stworzyłeś węzeł jako normalną klasę (niezwiązaną z ECS), czy używałeś innych podejść? Podziękować!
cppBeginner