Como trazer ordem à lógica de IA em jogos e robótica com a biblioteca Bonsai

Qualquer pessoa que já tentou programar o comportamento de um NPC complexo para um jogo ou de um robô autônomo usando máquinas de estados finitas (FSM) conhece esse momento de desespero. No início, tudo é simples: três estados ("patrulha", "perseguir", "atacar") e algumas transições. Mas o projeto cresce. Verificações de vida aparecem, reações a tiros por trás, procurar cobertura, recarregar arma. De repente, o grafo de transições se transforma em uma bagunça emaranhada de espaguete, onde adicionar uma nova ação quebra metade das conexões antigas.
O desenvolvimento de jogos há muito encontrou um remédio para essa dor na forma de Behavior Trees. Elas foram popularizadas na época por Halo 2 e Unreal Engine. Hoje, esse conceito é ativamente usado em robótica e sistemas autônomos.
Recentemente, me deparei com o Bonsai — uma implementação leve e rápida de behavior trees em Rust, com bindings Python incluídos pelo autor.
O que é uma Behavior Tree em palavras simples
Se descartarmos a terminologia acadêmica, uma behavior tree é uma estrutura hierárquica de regras que define a reação de um agente ao mundo. A principal vantagem dessa abordagem é a modularidade. Cada nó é isolado e retorna um de três status para seu pai:
Success(ação concluída com sucesso)Failure(ação falhou)Running(ação ainda está em execução)
O nó pai decide quem chamar em seguida com base nesse resultado.
No Bonsai, a lógica é montada a partir de vários tipos básicos de nós:
// Выполняет A, затем B. Если A падает, цепочка прерывается
Sequence([A, B])
// Пробует A. Если падает, пробует B
Select([A, B])
// Классическое ветвление
If(condition, A, B)
// Выполняет A и B параллельно, ожидая завершения обоих
WhenAll([A, B])
// Запускает параллельно и ждет первого завершившегося
Race([A, B])
A árvore é percorrida de cima para baixo, da esquerda para a direita. Se um inimigo desaparece do campo de visão durante o momento de mira, o ramo de interrupção reagirá instantaneamente no próximo ciclo de tick. Você não precisa escrever manualmente centenas de condições de saída para o estado atual, como em FSMs tradicionais.
Como o Bonsai funciona nos bastidores
O Bonsai é escrito em Rust puro sem overhead extra. Para adicioná-lo ao seu projeto, basta adicionar a dependência ao Cargo.toml:
[dependencies]
bonsai-bt = "*"
Se você está trabalhando em conjunto com Python (por exemplo, para prototipagem ou scripting de robôs no ROS), o pacote é instalado via pip:
pip install bonsai-bt
O problema de tarefas de longa duração
A behavior tree deve ser consultada regularmente e sem atrasos. Se algum nó interno bloquear a thread por meio segundo (digamos, executando pathfinding pesado ou uma requisição de rede para um sensor), todo o sistema congelará.
O autor do Bonsai resolveu esse problema através do status Running e canais de mensagens. Tarefas síncronas ou assíncronas de longa duração são movidas para threads em segundo plano. O nó da árvore simplesmente retorna Running em cada tick até que um sinal de conclusão ou erro chegue do canal. O repositório tem um exemplo claro de async drone demonstrando controle de drone em modo assíncrono.
Onde isso é útil
As tags do repositório não são por acaso relacionadas a ROS2, Bevy e Unreal Engine. Aqui estão cenários típicos onde o Bonsai salva seus nervos:
- Jogos em Bevy ou outros motores Rust. Para implementar IA de inimigos, aliados ou eventos procedurais.
- Robótica e drones. Construção de algoritmos de navegação determinísticos, desvio de obstáculos e execução de missões.
- Pipelines de backend com ramificação complexa. Se você tem uma cadeia de tarefas com retries, timeouts e ramificações paralelas, montá-la via Behavior Tree costuma ser mais conveniente do que construir instruções
matchetry/catchaninhadas.
Prós e contras
O projeto deixa uma impressão agradável com seu minimalismo. Não há abstrações sobrecarregadas aqui, o código é limpo e o determinismo da lógica torna o debug previsível.
No lado negativo: a documentação no próprio README é bastante breve. Para entender todas as nuances dos nós paralelos (WhileAll, After), você precisará olhar a pasta examples/ e os testes. Também não há editor visual de árvore pronto para uso, então você terá que construir a árvore em código.
Se você precisa de uma ferramenta clara, rápida e previsível para lógica de agentes em Rust ou Python sem dependências pesadas, o Bonsai definitivamente merece uma estrela no GitHub e um teste no seu projeto paralelo.
Projetos relacionados