目录

MoonBit Behavior Tree

CI License: Apache-2.0

一个使用纯 MoonBit 编写的、轻量、高性能且零外部依赖的行为树(Behavior Tree)决策引擎库。

适用于游戏 NPC AI 控制、智能体(Agent)的任务流程决策与复杂业务编排,支持 WebAssembly (wasm-gc)、JavaScript 以及 Native 全平台。

特性

模块 说明
Blackboard 共享键值上下文,支持 snapshot/restore 沙盒、事务、差异补丁与原子校验
Sequence 顺序节点(AND 门),支持跨帧 Running 状态恢复
Selector 选择节点(OR 门),支持跨帧 Running 状态恢复
Parallel 并行节点,SuccessAll/SuccessOne 策略可配置
RandomSelector 随机顺序选择(LCG 伪随机),适合非确定性 AI
Inverter 逆变修饰器(取反 Success/Failure)
Succeeder 始终成功修饰器
Repeater 重复N次修饰器
Limiter 执行频率限制修饰器
Retry 失败重试修饰器(最多N次)
UntilSuccess 持续重试直到成功
UntilFailure 持续重试直到失败
Timeout 超时降级修饰器(超过N帧强制Failure)
Action / Condition 叶子节点,Action 支持 Running 跨帧状态
EventBus 事件总线,支持 emit/consume/clear 与一次性 handler dispatch
EventRouter 有界 FIFO 事件路由,支持带 payload 事件、Running 跨帧处理和 fallback
InterruptNode 事件中断节点,外部事件抢占正在运行的子树
ConditionGuardNode 反应式前置条件守卫,持续监控断言
Scheduler 多树并发调度器,per-tree 独立黑板,支持暂停/恢复
BudgetScheduler 按优先级和每帧预算调度大量 NPC/Agent,支持暂停、重置和积压报告
Builder 链式声明式 API,结构自解释,极易维护
TraceNode 调试追踪包装器,实时打印 Tick 执行路径
TreeRunner 管理单棵树的黑板、帧计数、重置与终止运行
NodeMetrics 统计 Success/Failure/Running、连续 Running 与 CSV 快照
TraceBuffer 有界执行追踪窗口,支持环形保留、状态统计和 CSV 导出
Quorum / Race 阈值并行与竞速策略,适合多传感器或多代理协调
Safety policies 执行预算、once、cooldown、稳定状态与上下文守卫
Scenario harness 跨 wasm-gc/JS/Native 的可重复逻辑基准和 CSV 报告

安装

方法一:moon add(推荐)

moon add mhh12345678/behavior_tree

方法二:手动添加依赖

如果是手动配置依赖,首先在包目录的 moon.mod 中添加依赖声明:

[deps]
"mhh12345678/behavior_tree" = "0.1.2"

然后在你需要使用它的包的 moon.pkg 中导入:

import {
  "mhh12345678/behavior_tree" @bt
}

快速开始

// 1. 创建共享黑板
let bb = @bt.Blackboard::new()
bb.set_int("health", 45)
bb.set_bool("enemy_in_sight", true)

// 2. 使用 Builder 声明式构建行为树
let tree = @bt.Builder::new()
  .selector()
    // 血量低时逃跑(优先级最高)
    .sequence()
      .condition(fn(bb) { bb.get_int("health").unwrap_or(100) < 50 })
      .action(fn(_) { println("Low health! Fleeing..."); @bt.BTSuccess })
      .end()
    // 发现敌人则追击
    .sequence()
      .condition(fn(bb) { bb.get_bool("enemy_in_sight").unwrap_or(false) })
      .action(fn(_) { println("Enemy spotted! Chasing..."); @bt.BTSuccess })
      .end()
    // 默认巡逻
    .action(fn(_) { println("Patrolling..."); @bt.BTSuccess })
    .end()
  .build()

// 3. 执行单次 Tick
let status = tree.tick(bb)
println("Result: \{status.to_string()}")
// 输出: Low health! Fleeing...
// 输出: Result: Success

高级用法

事件中断(InterruptNode)

let bus = @bt.EventBus::new()
let tree = @bt.interrupt_node(bus, "enemy_spotted", patrol_tree, attack_tree)

// 在任意时刻发出事件,下一次 tick 会切换到 attack_tree
bus.emit("enemy_spotted")
let _ = tree.tick(bb)

如果应用更适合使用闭包处理事件,也可以注册 handler 并显式派发;事件最多被派发一次:

bus.on("damage", fn(bb) {
  bb.set_int("last_damage", 5)
  @bt.BTSuccess
})
bus.emit("damage")
let _ = bus.dispatch("damage", bb)

多 NPC 并发调度(Scheduler)

let sched = @bt.Scheduler::new()
sched.add(@bt.SchedulerEntry::new("guard1", guard_tree, @bt.Blackboard::new()))
sched.add(@bt.SchedulerEntry::new("guard2", patrol_tree, @bt.Blackboard::new()))

// 单次帧调用,所有 NPC 同时 tick
let results = sched.tick()
for r in results {
  println("\{r.name}: \{r.status.to_string()}")
}

黑板快照沙盒

bb.set_int("hp", 100)
bb.snapshot()         // 保存当前状态
bb.set_int("hp", 0)   // 模拟伤害
// 测试沙盒内的行为...
bb.restore()          // 回滚到快照
// bb.get_int("hp") == Some(100)

原子状态事务与差异补丁

复杂动作可以先在隔离黑板中试算,只有校验通过才提交;这适合商店购买、战斗规划、存档和网络同步:

let before = bb.clone()
let accepted = bb.transactional(fn(working) {
  working.set_int("credits", working.get_int_or("credits", 0) - 20)
  working.set_string("last_action", "buy_potion")
  working.get_int_or("credits", 0) >= 0
})
let patch = before.diff(bb)
let _ = patch.to_text()

有界事件路由

EventRouter 将消息队列接入帧循环,每帧最多处理固定数量事件;返回 Running 的 handler 会自动保留原事件,适合资源加载、网络重试和多帧动画:

let queue = @bt.EventQueue::new()
let router = @bt.EventRouter::new(queue, 4)
let _ = router.on("damage", fn(bb, event) {
  bb.set_int("last_damage", event.payload().unwrap().as_int().unwrap())
  @bt.BTSuccess
})
let _ = queue.emit_value("damage", @bt.Value::Int(5))
let report = router.tick(bb)
println(report.to_line())

优先级与帧预算调度

当场景中有大量独立 NPC 或 Agent 时,可使用 BudgetScheduler 避免单帧工作量失控:

let scheduler = @bt.BudgetScheduler::new(8)
let _ = scheduler.add(
  @bt.BudgetTask::new("guard-1", 10, guard_tree, @bt.Blackboard::new()),
)
let report = scheduler.tick()
println("pending=\{report.pending()}, skipped=\{report.skipped()}")

有界执行追踪

TraceBuffer 只保留最近 N 条节点结果,不会让长时间运行的服务无限增长日志内存:

let trace = @bt.TraceBuffer::new(256)
let traced = @bt.trace_buffer_node("combat", combat_tree, trace)
let _ = traced.tick(bb)
println(trace.to_csv())

项目结构

.
├── blackboard.mbt          # 黑板上下文(snapshot/restore)
├── blackboard_patch.mbt    # 事务、差异补丁和原子状态提交
├── node.mbt                # Status / Ref / Node / Sequence / Selector / Parallel / RandomSelector
├── decorator.mbt           # 8 种修饰器节点
├── leaf.mbt                # Action / Condition 叶子节点
├── builder.mbt             # 链式 Builder API
├── parser.mbt              # Trace 调试节点包装器
├── event.mbt               # EventBus / InterruptNode / ConditionGuardNode
├── event_router.mbt        # 有界 payload 事件路由器
├── scheduler.mbt           # 多树 Scheduler 调度器
├── budget_scheduler.mbt    # 优先级与帧预算调度器
├── helpers.mbt             # 便捷工厂函数
├── runtime.mbt / telemetry.mbt / health.mbt # 运行时生命周期与可观测性
├── trace_buffer.mbt        # 有界环形执行追踪
├── policy_nodes.mbt / safety.mbt / quorum.mbt # 生产策略与安全边界
├── benchmark.mbt / scenario.mbt # 可重复基准和场景矩阵
├── behavior_tree_wbtest.mbt # 核心单元测试
├── integration_test.mbt / boundary_test.mbt # 集成与边界测试
├── production_runtime_test.mbt # 事务、路由、追踪和预算调度场景
├── lib_doc.mbt             # 库文档快速入门示例
├── cmd/main/main.mbt       # 守卫 NPC AI 仿真演示
└── .github/workflows/ci.yml # CI:wasm-gc / js / native 全平台

运行与测试

# 类型检查(全平台)
moon check --target all

# 执行 80 个测试用例(全部通过)
moon test --target all

# 运行守卫 NPC AI 仿真演示
moon run cmd/main

可重复基准

基准只统计逻辑 Tick 与三种状态,不依赖机器时钟,因此可在不同后端和 CI 上复现:

let csv = @bt.standard_benchmark_csv()
println(csv)

当前固定场景为启用工作流、禁用工作流和带执行预算的持续运行节点;边界覆盖空集合、零/负预算、阈值恰好命中、缺失黑板键、嵌套快照回滚和独立黑板克隆。

严格验收命令

moon fmt --check
moon check --deny-warn
moon test --deny-warn
moon info
moon run cmd/main

本地 Native 构建需要系统 C 编译器;CI 会在 Linux、macOS、Windows 上执行标准检查。仓库当前有效 .mbt 源码超过 5200 行,其中排除测试后的生产代码约 4200 行;生成目录 _build/ 不计入源码规模。

示例输出

=== MoonBit Behavior Tree Guard AI Simulation ===

--- Tick 1: Patrol mode ---
-> Tick: Patrol Action
AI ACTION: Patrol waypoint 1
<- Patrol Action Result: Success

--- Tick 3: Enemy spotted at distance 8.0 ---
-> Tick: Combat Branch
AI ACTION: Chasing enemy... distance 5
<- Combat Branch Result: Running

--- Tick 7: Guard HP=20, flees ---
-> Tick: Flee Branch
AI ACTION: Low health! Fleeing...
<- Flee Branch Result: Success

许可证

本项目采用 Apache-2.0 开源许可证。

项目代码为原创 MoonBit 实现,未复制第三方源文件或生成代码;行为树概念仅参考公开算法资料。测试与示例均为本仓库原创,第三方依赖为空。若未来引入外部代码、数据集或生成文件,必须在本节或单独的 NOTICE/THIRD_PARTY.md 中记录来源、版本、许可证和再分发范围。


参考资料

关于

moonbit-behavior-tree 是一个针对游戏 AI 与智能体(Agent)开发设计的行为树引擎库。项目使用纯 MoonBit 开发,提供包括 Composite(顺序、选择、并行)、Decorator(逆变、重复、限流等)及 Leaf(动作、条件)在内的完整节点模型,内置共享内存 Blackboard(黑板)系统,支持流式 Builder 构建与调试追踪。项目具有零依赖、高性能、跨平

301.0 KB
邀请码
    Gitlink(确实开源)
  • 加入我们
  • 官网邮箱:gitlink@ccf.org.cn
  • QQ群
  • QQ群
  • 公众号
  • 公众号

版权所有:中国计算机学会技术支持:开源发展技术委员会
京ICP备13000930号-9 京公网安备 11010802047560号