mcpField
B
beehave

beehave

github.com/jame581开发889137 次安装4 天前更新
代码仓库

关于 beehave

Beehave 是面向 Godot 4.1+、以 GDScript 编写的轻量行为树插件,适合希望通过场景树组织游戏 AI 的项目。它提供组合节点、装饰器、黑板和运行时可视化调试器。

主要功能

  1. 01场景树节点式行为树
  2. 02组合节点与装饰器
  3. 03共享黑板键值存储
  4. 04运行时行为树可视化
  5. 05可调节树的执行频率

适用场景

  1. 01为游戏角色编排 AI 行为
  2. 02组合攻击条件与巡逻动作
  3. 03在多个行为树间共享状态
  4. 04运行时检查行为树节点执行

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/jame581/godotprompter --skill beehave

安装后在 Claude Code 中输入/beehave确认已加载。

附带文件references/custom-nodes.md

详细介绍

Beehave

**相关技能:**移动叶节点使用 ai-navigation,核心引擎 FSM 使用 state-machine,更重量级的 C++ BT+HSM 替代方案使用 limboai,选择 AI 方案使用 godot-brainstorming。

**插件:**Beehave · 版本 v2.9.2 · Godot 4.1+ · MIT · 源码:https://github.com/bitbrain/beehave · 使用 GDScript 编写(没有官方 C# API——本技能特意仅支持 GDScript)。


1. 何时使用 Beehave

方案最适用于
核心引擎 FSM(state-machine 技能)简单 Agent、< 5 个状态、无需插件
Beehave(GDScript 插件)轻量级 BT、仅使用 GDScript 的项目、快速迭代
LimboAI同时使用 BT 和 HSM、可视化编辑器、C++ 性能、支持 C#(模块构建)

当项目仅使用 GDScript、希望使用行为树而无需自定义引擎构建,并且重视简单的场景树节点创作工作流时,选择 Beehave。Beehave 树完全位于场景树中——每个复合节点、装饰器和叶节点都是常规的 Node 子节点。若要使用集成 HSM 的重量级 C++/C# 方案,请改用 limboai 技能。若要使用不带 BT 的普通状态机,请使用内置的 state-machine 技能。

**C# 说明:**Beehave 没有官方 C# API(addons/beehave/ 中没有任何 .cs 文件)。在 C# 中,你可以通过 Godot 跨语言互操作调用 GDScript API(GetNode<Node>(...).Call("tick", actor, blackboard)),但 Beehave 不提供强类型的 C# 类。


2. 安装与启用

  1. Godot AssetLib → 搜索“Beehave” → 下载 → 重新加载项目。
    或者将 GitHub 发布页中的 addons/beehave/ 文件夹复制到 res://addons/beehave/。
  2. 启用插件:Project → Project Settings → Plugins → 勾选 Beehave。
    系统会注册两个自动加载项:BeehaveGlobalMetrics 和 BeehaveGlobalDebugger。
  3. 可选——将插件中的 script_templates/ 复制到项目根目录,用作叶节点脚手架模板。

3. 树的构成

Beehave 树由三类节点构成,它们都作为常规场景树子节点放置:

角色节点行为
树根BeehaveTree每帧(或物理帧/手动)对其子节点执行 Tick;继承自 Node(而非 BeehaveNode)
复合节点SequenceComposite、SelectorComposite、SimpleParallelComposite、…流程控制——AND / OR / 并行逻辑
装饰器InverterDecorator、CooldownDecorator、RepeaterDecorator、…包装一个子节点以修改其结果
叶节点ActionLeaf、ConditionLeaf 子类你的自定义游戏逻辑
复合节点速查
类逻辑
SequenceCompositeAND——所有子节点都必须成功;遇到第一个失败的子节点时失败
SequenceReactiveCompositeAND——运行期间,每次 Tick 都从第一个子节点开始重新评估
SelectorCompositeOR——遇到第一个成功的子节点时成功;所有子节点都失败时才失败
SelectorReactiveCompositeOR——运行期间,每次 Tick 都从第一个子节点开始重新评估
SimpleParallelComposite同时运行两个子节点;结果取决于主子节点(子节点 0)
SequenceRandomComposite随机排序的 AND——按随机顺序执行子节点
SelectorRandomComposite随机排序的 OR——按随机顺序尝试子节点
装饰器速查表
类效果
InverterDecorator翻转 SUCCESS ↔ FAILURE;RUNNING 状态原样传递
AlwaysSucceedDecorator强制返回 SUCCESS;RUNNING 状态原样传递
AlwaysFailDecorator强制返回 FAILURE;RUNNING 状态原样传递
RepeaterDecorator重新运行子节点,直到其成功达到 repetitions 次
LimiterDecorator将子节点限制为最多运行 max_count 个 tick,之后返回 FAILURE
CooldownDecorator子节点结束后,在 wait_time 秒内阻止再次执行
TimeLimiterDecorator给子节点 wait_time 秒;如果仍在运行,则中断它
DelayDecorator等待 wait_time 秒后再首次执行子节点
UntilFailDecorator循环运行子节点,直到其返回 FAILURE,然后返回 SUCCESS
最简场景树示例
# Scene tree:
#   Enemy (CharacterBody2D)
#     BeehaveTree               ← tick_rate = 1, process_thread = PHYSICS
#       SelectorComposite
#         SequenceComposite     ← "attack if in range"
#           IsInRangeCondition
#           AttackAction
#         PatrolAction          ← fallback

# BeehaveTree exports:
# @export var enabled: bool = true
# @export var tick_rate: int = 1          (1 = every frame; 3 = every 3 frames)
# @export var process_thread: ProcessThread = PHYSICS
# @export var blackboard: Blackboard      (auto-created if not set)
# @export_node_path var actor_node_path   (defaults to parent node)

# Access the tree from code if you need manual control:
@onready var bt: BeehaveTree = $BeehaveTree

func _ready() -> void:
    # Reduce tick cost: evaluate AI every 3 physics frames
    bt.tick_rate = 3
    # Default process_thread is PHYSICS — switch to IDLE if actor uses _process
    bt.process_thread = BeehaveTree.ProcessThread.IDLE

tick_rate 说明:tick_rate = 1 表示每帧都会进行求值;tick_rate = 3 表示每 3 帧进行一次求值。对于距离较远或处于后台的 NPC,可调高该值以节省 CPU。默认处理线程为 PHYSICS——如果角色脚本使用 _process 而非 _physics_process,请将 process_thread = IDLE,使它们保持同步。


4. 叶节点约定

叶节点负责承载你的游戏逻辑。对于需要跨多个 tick 执行的工作,继承 ActionLeaf;对于单帧检查,继承 ConditionLeaf,然后重写 tick(actor, blackboard)。

# IsInRangeCondition.gd
class_name IsInRangeCondition
extends ConditionLeaf

@export var detection_range: float = 150.0

func tick(actor: Node, blackboard: Blackboard) -> int:
    # Beehave types `actor` as Node; cast to your concrete type for 2D members.
    var body := actor as Node2D
    var target: Node2D = blackboard.get_value("target")
    if body == null or not is_instance_valid(target):
        return FAILURE
    var in_range := body.global_position.distance_to(target.global_position) <= detection_range
    return SUCCESS if in_range else FAILURE
# AttackAction.gd
class_name AttackAction
extends ActionLeaf

@export var attack_duration: float = 0.5

func tick(actor: Node, blackboard: Blackboard) -> int:
    var elapsed: float = blackboard.get_value("attack_elapsed", 0.0)
    elapsed += get_physics_process_delta_time()

    if elapsed >= attack_duration:
        blackboard.erase_value("attack_elapsed")
        # `actor` is typed Node; guard game-specific methods (or cast to your actor type).
        if actor.has_method("play_attack_animation"):
            actor.call("play_attack_animation")
        return SUCCESS

    blackboard.set_value("attack_elapsed", elapsed)
    return RUNNING

func interrupt(actor: Node, blackboard: Blackboard) -> void:
    # Clean up per-run state when the tree interrupts this action (after_run is not called then)
    blackboard.erase_value("attack_elapsed")
    super(actor, blackboard)  # keeps the debugger's interrupt message

返回码(定义于 BeehaveNode):

  • SUCCESS — 动作完成/条件满足。
  • FAILURE — 动作失败/条件不满足;由父复合节点决定下一步操作。
  • RUNNING — 动作需要更多帧;行为树会在下一帧再次调用 tick()(仅限 ActionLeaf——ConditionLeaf 不应返回 RUNNING)。

可选重写方法:

  • before_run(actor, blackboard) — 在一次运行的首次 tick 之前调用一次。
  • after_run(actor, blackboard) — 在返回 SUCCESS/FAILURE 的 tick 之后调用;中断时不会调用。
  • interrupt(actor, blackboard) — 当行为树中断正在运行的节点时调用。

5. 黑板

Blackboard 节点是一个共享的键值存储,会传递给每次 tick() 调用。如果你没有指定外部 Blackboard 节点,BeehaveTree 会自动创建一个内部节点。

# Share one Blackboard across multiple BeehaveTrees on the same actor.
# Assign the same exported Blackboard node to each tree in the Inspector.

# Read / write from any leaf's tick():
func tick(actor: Node, blackboard: Blackboard) -> int:
    # Write
    blackboard.set_value("target", actor.get_nearest_enemy())

    # Read with default
    var speed: float = blackboard.get_value("move_speed", 200.0)

    # Conditional check
    if blackboard.has_value("stunned"):
        return FAILURE

    # Erase (sets key to null; has_value returns false after erase)
    blackboard.erase_value("temp_flag")

    return SUCCESS

命名空间:set_value、get_value、has_value 和 erase_value 接受可选参数 blackboard_name: String(默认为 "default")。你可以用它在同一个 Blackboard 节点上维护不同的命名空间,避免名称冲突(例如,按敌人区分状态与共享世界状态)。

内置表达式叶节点:BlackboardSetAction、BlackboardEraseAction、BlackboardHasCondition 和 BlackboardCompareCondition 可让你完全通过 Inspector 导出属性操作 Blackboard(无需 GDScript)。表达式通过 Godot 的 Expression.execute([], blackboard) 运行,因此你可以直接在表达式字符串中调用 get_value("key")。


6. 可视化调试器

Beehave 附带一个 EditorDebuggerPlugin,在游戏运行时会在编辑器底部面板中添加 🐝 Beehave 标签页:

  1. 从 Godot 编辑器运行项目。
  2. 打开 Debugger 面板 → 点击 🐝 Beehave 标签页。
  3. 从列表中选择一棵树以启用实时可视化——每次 tick 时,活动节点都会高亮显示。
  4. 可选:点击分离按钮以浮动显示面板;或者将 Project Settings → beehave/debugger/start_detached = true 设为启用,使面板始终以分离状态启动。

若要在 Performance 面板中跟踪每棵树的 CPU 开销,请在 BeehaveTree 节点上将 custom_monitor = true。这会注册 beehave [microseconds]/process_time_<actor_name>-<id> 作为 Performance 监视器。

有关编写自定义装饰器和条件节点的教程,请参阅 references/custom-nodes.md。


实施清单

  • 已将 addons/beehave/ 复制到项目中;已在 项目设置 → 插件 中启用插件
  • 已将 BeehaveTree 添加为 actor 的子节点;已设置 actor_node_path(或留空以默认指向父节点)
  • process_thread 与 actor 的循环匹配:_physics_process 使用 PHYSICS,_process 使用 IDLE
  • 已调整 tick_rate——提高后台 NPC 的值(例如 3),以降低每帧开销
  • 每个 tick() 重写都返回 SUCCESS、FAILURE 或 RUNNING——绝不返回 void/null
  • ConditionLeaf 子类绝不返回 RUNNING
  • 每次运行的状态写入 Blackboard,而不是存储在叶节点本身
  • after_run 或 interrupt 会清理该动作写入的所有 Blackboard 键
  • 当多个 BeehaveTree 节点需要共享相同数据时,导出并共享外部 Blackboard 节点
  • 发货 AI 逻辑前,在运行时检查可视化调试器,验证 tick 流程

评论

支持 Markdown