Jak uporządkować logikę AI w grach i robotyce dzięki bibliotece Bonsai

Każdy, kto próbował kiedykolwiek zaprogramować zachowanie złożonego NPC w grze lub autonomicznego robota za pomocą maszyn stanowych (FSM), zna ten moment rozpaczy. Na początku wszystko jest proste: trzy stany ("patrol", "pościg", "atak") i garść przejść. Ale projekt rośnie. Pojawiają się kontrole zdrowia, reakcje na strzały z tyłu, szukanie osłony, przeładowywanie broni. Nagle graf przejść zamienia się w splątany kłębek spaghetti, gdzie dodanie jednej nowej akcji psuje połowę starych połączeń.
Twórcy gier od dawna znaleźli remedium na ten ból w postaci drzew zachowań (Behavior Trees). Spopularyzowała je w swoim czasie gra Halo 2 i silnik Unreal Engine. Dziś ten koncept jest aktywnie wykorzystywany w robotyce i systemach autonomicznych.
Ostatnio natknąłem się na Bonsai — lekką i szybką implementację drzew zachowań w Rust, z powiązaniami Pythona dorzuconymi przez autora.
Czym jest drzewo zachowań w prostych słowach
Jeśli odrzucimy akademicką terminologię, drzewo zachowań to hierarchiczna struktura reguł określająca reakcję agenta na świat. Główną zaletą tego podejścia jest modularność. Każdy węzeł jest odizolowany i zwraca jeden z trzech statusów do swojego rodzica:
Success(akcja zakończona sukcesem)Failure(akcja nie powiodła się)Running(akcja wciąż trwa)
Węzeł nadrzędny decyduje, kogo wywołać dalej na podstawie tego wyniku.
W Bonsai logika jest składana z kilku podstawowych typów węzłów:
// Выполняет A, затем B. Если A падает, цепочка прерывается
Sequence([A, B])
// Пробует A. Если падает, пробует B
Select([A, B])
// Классическое ветвление
If(condition, A, B)
// Выполняет A и B параллельно, ожидая завершения обоих
WhenAll([A, B])
// Запускает параллельно и ждет первого завершившегося
Race([A, B])
Drzewo jest przechodzone od góry na dół, od lewej do prawej. Jeśli wróg zniknie z pola widzenia właśnie podczas celowania, gałąź przerwania zareaguje natychmiast w następcyklu ticków. Nie musisz ręcznie pisać setek warunków wyjścia dla bieżącego stanu, jak w zwykłych FSM-ach.
Jak działa Bonsai pod maską
Bonsai jest napisany w czystym Rust bez dodatkowego narzutu. Aby dodać go do swojego projektu, wystarczy dodać zależność do Cargo.toml:
[dependencies]
bonsai-bt = "*"
Jeśli pracujesz w tandemie z Pythonem (na przykład do prototypowania lub skryptowania robotów na ROS), pakiet instaluje się przez pip:
pip install bonsai-bt
Problem długotrwałych zadań
Drzewo zachowań musi być odpytywane regularnie i bez opóźnień. Jeśli jakiś węzeł wewnątrz zablokuje wątek na pół sekundy (powiedzmy, wykonując ciężkie wyszukiwanie ścieżki lub żądanie sieciowe do czujnika), cały system się zamrozi.
Autor Bonsai rozwiązał ten problem poprzez status Running i kanały komunikatów. Długotrwałe zadania synchroniczne lub asynchroniczne są przenoszone do wątków w tle. Węzeł drzewa po prostu zwraca Running przy każdym ticku, dopóki nie nadejdzie sygnał zakończenia lub błędu z kanału. W repozytorium znajduje się wyraźny przykład async drone demonstrujący sterowanie dronem w trybie asynchronicznym.
Gdzie to się przydaje
Tagi repozytorium nie są przypadkowe — znajdziesz tam ROS2, Bevy i Unreal Engine. Oto typowe scenariusze, gdzie Bonsai ratuje nerwy:
- Gry na Bevy lub innych silnikach Rust. Do implementacji AI wrogów, sojuszników lub zdarzeń proceduralnych.
- Robotyka i drony. Budowanie deterministycznych algorytmów nawigacji, unikania przeszkód i wykonywania misji.
- Potoki backendowe ze złożonym rozgałęzieniem. Jeśli masz łańcuch zadań z ponownymi próbami, timeoutami i gałęziami równoległymi, składanie go przez drzewo zachowań jest często wygodniejsze niż budowanie zagnieżdżonych instrukcji
matchitry/catch.
Plusy i minusy
Projekt pozostawia przyjemne wrażenie dzięki swojemu minimalizmowi. Nie ma tutaj przeciążonych abstrakcji, kod jest czysty, a determinizm logiki sprawia, że debugowanie jest przewidywalne.
Wadą jest: dokumentacja w samym README jest dość zwięzła. Aby zrozumieć wszystkie niuanse węzłów równoległych (WhileAll, After), musisz zajrzeć do folderu examples/ i testów. Nie ma również wbudowanego wizualnego edytora drzew, więc będziesz musiał budować drzewo w kodzie.
Jeśli potrzebujesz jasnego, szybkiego i przewidywalnego narzędzia do logiki agentów w Rust lub Pythonie bez ciężkich zależności, Bonsai zdecydowanie zasługuje na gwiazdkę na GitHub i na przetestowanie w Twoim pobocznym projekcie.
Powiązane projekty