如何用 Bonsai 库为游戏和机器人 AI 逻辑带来秩序

任何曾尝试使用有限状态机(FSM)为游戏中的复杂 NPC 或自主机器人编程行为的人,都经历过这种绝望的时刻。一开始,一切都很简单:三个状态("巡逻"、"追击"、"攻击")和几个转换。但项目在增长。出现了生命值检查、被背后射击的反应、寻找掩体、武器换弹。突然间,转换图变成了一团混乱的意大利面条,其中添加一个新动作就会破坏一半的旧连接。
游戏开发早就在行为树中找到了解决这一痛苦的良方。它们在当年由 Halo 2 和 Unreal Engine 推广开来。如今,这个概念被广泛应用于机器人和自主系统领域。
最近,我偶然发现了 Bonsai——一个用 Rust 实现的轻量级、快速的行为树,并附带 Python 绑定。
用通俗的话来说,什么是行为树
如果我们抛开学术术语,行为树是一种层级化的规则结构,用于定义智能体对世界的反应。这种方法的主要优势是模块化。每个节点都是独立的,并向其父节点返回三种状态之一:
Success(动作成功完成)Failure(动作失败)Running(动作仍在运行)
父节点根据这个结果决定下一步调用谁。
在 Bonsai 中,逻辑由几种基本节点类型组合而成:
// Выполняет A, затем B. Если A падает, цепочка прерывается
Sequence([A, B])
// Пробует A. Если падает, пробует B
Select([A, B])
// Классическое ветвление
If(condition, A, B)
// Выполняет A и B параллельно, ожидая завершения обоих
WhenAll([A, B])
// Запускает параллельно и ждет первого завершившегося
Race([A, B])
树从上到下、从左到右遍历。如果在瞄准过程中敌人从视野中消失,中断分支会在下一个 tick 周期立即做出反应。你不需要像传统 FSM 那样手动编写数百个当前状态的退出条件。
Bonsai 底层是如何工作的
Bonsai 使用纯 Rust 编写,没有额外的开销。要将其添加到你的项目中,只需在 Cargo.toml 中添加依赖:
[dependencies]
bonsai-bt = "*"
如果你与 Python 协同工作(例如,用于原型设计或在 ROS 上编写机器人脚本),可以通过 pip 安装该包:
pip install bonsai-bt
长时间运行任务的问题
行为树必须定期且无延迟地被轮询。如果内部某个节点阻塞线程半秒钟(例如,执行重型路径规划或向传感器发出网络请求),整个系统就会冻结。
Bonsai 的作者通过 Running 状态和消息通道解决了这个问题。长时间运行的同步或异步任务被移到后台线程。树节点在每个 tick 中简单地返回 Running,直到从通道接收到完成或错误信号。仓库中有一个清晰的 async drone 示例,演示了在异步模式下控制无人机。
这在哪里派上用场
仓库标签中并非巧合地出现了 ROS2、Bevy 和 Unreal Engine。以下是 Bonsai 能为你省心的典型场景:
- 使用 Bevy 或其他 Rust 引擎的游戏。用于实现敌人 AI、盟友或程序化事件。
- 机器人和无人机。构建确定性导航算法、障碍物规避和任务执行。
- 具有复杂分支的后端管道。如果你有一个包含重试、超时和并行分支的任务链,通过行为树来组装通常比构建嵌套的
match和try/catch语句更方便。
优点和缺点
这个项目以其极简主义留下了令人愉悦的印象。这里没有过度设计的抽象,代码干净,逻辑的确定性使调试可预测。
缺点方面:README 本身的文档相当简略。要理解并行节点(WhileAll、After)的所有细节,你需要查看 examples/ 文件夹和测试。此外,开箱即用没有可视化树编辑器,所以你必须通过代码来构建树。
如果你需要一个清晰、快速且可预测的 Rust 或 Python 智能体逻辑工具,而不需要重量级的依赖项,Bonsai 绝对值得在 GitHub 上点个星,并在你的副项目中进行测试。
相关项目