beehave について
Beehave は GDScript 製の Godot 4.1+ 向け軽量ビヘイビアツリープラグインです。シーンツリーでゲーム AI を構成するプロジェクトに適しており、コンポジット、デコレーター、Blackboard、実行時の可視化機能を備えます。
主な機能
- 01シーンツリー形式のビヘイビアツリー
- 02コンポジットとデコレーター
- 03共有 Blackboard のキー・バリューストア
- 04実行時のビヘイビアツリー可視化
- 05ツリーの実行頻度調整
活用シーン
- 01ゲームキャラクターの AI 行動を構成
- 02攻撃条件と巡回アクションを組み合わせ
- 03複数のビヘイビアツリー間で状態を共有
- 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 スキル) | シンプルなエージェント、状態が 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 ファイルは 0 個です)。C# からは Godot の言語間相互運用機能を使って GDScript API を呼び出せます(GetNode<Node>(...).Call("tick", actor, blackboard))が、Beehave は型付きの C# クラスを提供していません。
2. インストールと有効化
- Godot AssetLib → 「Beehave」を検索 → ダウンロード → プロジェクトを再読み込みします。
または、GitHub release からaddons/beehave/フォルダーをres://addons/beehave/にコピーします。 - プラグインを有効にします:Project → Project Settings → Plugins → Beehave にチェックを入れます。
2 つのオートロードが登録されます:BeehaveGlobalMetricsとBeehaveGlobalDebugger。 - 任意 — リーフのひな形テンプレートを使う場合は、アドオンの
script_templates/をプロジェクトのルートにコピーします。
3. ツリーの構成
Beehave のツリーは、通常のシーンツリーの子ノードとして配置する、次の 3 種類のノードで構成されます。
| 役割 | ノード | 動作 |
|---|---|---|
| ツリーのルート | BeehaveTree | 毎フレーム(または物理フレーム/手動)子ノードをティックします。BeehaveNode ではなく Node を継承します |
| コンポジット | SequenceComposite、SelectorComposite、SimpleParallelComposite、… | フロー制御 — AND/OR/並列ロジック |
| デコレーター | InverterDecorator、CooldownDecorator、RepeaterDecorator、… | 1 つの子ノードをラップして、その結果を変更します |
| リーフ | ActionLeaf、ConditionLeaf のサブクラス | 独自のゲームロジック |
コンポジットのクイックリファレンス
| クラス | ロジック |
|---|---|
SequenceComposite | AND — すべての子ノードが成功する必要があります。最初の失敗で失敗します |
SequenceReactiveComposite | AND — 実行中は、毎ティック最初の子ノードから再評価します |
SelectorComposite | OR — 最初に成功した時点で成功します。すべて失敗すると失敗します |
SelectorReactiveComposite | OR — 実行中は、毎ティック最初の子ノードから再評価します |
SimpleParallelComposite | 2 つの子ノードを同時に実行します。結果はプライマリ(子ノード 0)に従います |
SequenceRandomComposite | シャッフルした AND — 子ノードをランダムな順序で実行します |
SelectorRandomComposite | シャッフルした OR — 子ノードをランダムな順序で試します |
デコレーター早見表
| クラス | 効果 |
|---|---|
InverterDecorator | SUCCESS と FAILURE を反転し、RUNNING はそのまま通します |
AlwaysSucceedDecorator | SUCCESS を強制し、RUNNING はそのまま通します |
AlwaysFailDecorator | FAILURE を強制し、RUNNING はそのまま通します |
RepeaterDecorator | 子ノードが repetitions 回成功するまで再実行します |
LimiterDecorator | 子ノードの実行ティック数を max_count に制限し、その後 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フレームごとに評価します。CPU 使用量を抑えるには、遠くにいる NPC やバックグラウンドの NPC では値を大きくしてください。デフォルトのプロセススレッドはPHYSICSです。アクタースクリプトが_physics_processではなく_processを使用する場合は、同期を保つためにprocess_thread = IDLEを設定してください。
4. リーフの仕様
リーフにはゲームロジックを記述します。複数ティックにわたる処理には 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)— 実行の最初のティックの前に一度呼び出されます。after_run(actor, blackboard)—SUCCESS/FAILUREを返すティックの後に呼び出されます。中断時には呼び出されません。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")。これを使用すると、名前の衝突を避けて、1つのBlackboardノード上で名前空間を分けられます(例:敵ごとの状態と共有ワールド状態)。
組み込み式リーフ:
BlackboardSetAction、BlackboardEraseAction、BlackboardHasCondition、BlackboardCompareConditionを使うと、Inspector のエクスポート項目だけで Blackboard を操作できます(GDScript は不要です)。式は Godot のExpression.execute([], blackboard)で実行されるため、式の文字列内でget_value("key")を直接呼び出せます。
6. ビジュアルデバッガー
Beehave には EditorDebuggerPlugin が含まれており、ゲームの実行中にエディタ下部のパネルに 🐝 Beehave タブが追加されます。
- Godot エディタからプロジェクトを実行します。
- Debugger パネルを開き、🐝 Beehave タブをクリックします。
- リストからツリーを選択してライブ表示を有効にします。アクティブなノードは各ティックでハイライト表示されます。
- 任意:切り離しボタンをクリックしてパネルをフローティング表示にするか、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_node_pathを設定した(または空欄のままにして親をデフォルトにした) -
process_threadをアクターのループに合わせた:_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 ロジックをリリースする前に、実行時にビジュアルデバッガーでティックの流れを確認する