mcpField
A
ai-navigation

ai-navigation

github.com/jame581開発889180 回インストール4 日前に更新
リポジトリ

ai-navigation について

Godot 4.3+でAIナビゲーションを実装する開発者向けのスキルです。GDScriptとC#で2D・3Dの経路探索やステアリングを扱い、ビヘイビアツリーや追跡・攻撃パターンも紹介します。

主な機能

  1. 01NavigationAgent2D/3Dの経路探索
  2. 02ナビゲーションのベイクとレイヤー
  3. 03Seek、Flee、Arrive、Wanderのステアリング
  4. 04ウェイポイント巡回パターン
  5. 05ビヘイビアツリーと追跡・攻撃パターン

活用シーン

  1. 012Dまたは3Dの敵に経路移動を設定
  2. 02動的なレベルでナビゲーションメッシュを再構築
  3. 03巡回・追跡・攻撃ロジックを実装

インストール

コマンドをコピーしてターミナルで実行します。

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

インストール後、Claude Code で/ai-navigationを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
async-baking.md
behavior-trees.md
chase-attack.md
navigation-agent-3d.md
patrol-patterns.md
steering-behaviors.md

詳細

Godot 4.3+ の AI ナビゲーション

NavigationAgent2D/3D、ステアリング動作、ビヘイビアツリー、パトロールパターンについて説明します。すべての例は、非推奨 API を使用せず、Godot 4.3+ を対象としています。

関連スキル: AI の状態管理には state-machine、モジュール式の AI 動作には component-system、移動物理パターンには player-controller、経路探索のベクトルとステアリングの計算には math-essentials、ビジュアルエディターを備えた BT + HSM には limboai、軽量な GDScript ビヘイビアツリーには beehave が適しています。ステアリング/ナビゲーションではなく、構造化されたビヘイビアツリーについては、limboai と beehave の比較表を参照してください。


1. ナビゲーションのセットアップ

シーン構成
World (Node2D or Node3D)
└── NavigationRegion2D (or NavigationRegion3D)
    ├── TileMapLayer / StaticBody2D (geometry)
    └── Enemy (CharacterBody2D with NavigationAgent2D child)
NavigationRegion2D / NavigationRegion3D
  1. シーンに NavigationRegion2D(または NavigationRegion3D)ノードを追加します。
  2. NavigationPolygon(2D)または NavigationMesh(3D)リソースを割り当てます。
  3. NavigationPolygon エディターで歩行可能なエリアを描画するか、3D で NavigationMesh の境界を設定します。
  4. 編集時にメッシュをベイクします: NavigationRegion ノードを選択し、ツールバーで Bake NavigationPolygon(2D)または Bake NavigationMesh(3D)をクリックします。
  5. ワールドが動的に変化する場合は、実行時にベイクします:
# 2D
$NavigationRegion2D.bake_navigation_polygon()

# 3D
$NavigationRegion3D.bake_navigation_mesh()
// 2D
GetNode<NavigationRegion2D>("NavigationRegion2D").BakeNavigationPolygon();

// 3D
GetNode<NavigationRegion3D>("NavigationRegion3D").BakeNavigationMesh();
非同期ナビゲーションのベイク

大きなマップではナビゲーションのベイクによってフレーム落ちが発生することがあるため、リージョンはデフォルトでバックグラウンドスレッド上でベイクします。bake_navigation_polygon()(2D)と bake_navigation_mesh()(3D)は、false を渡さない限り on_thread = true で実行されます。メッシュの準備完了を確認するには、リージョンの bake_finished シグナルに接続します(CONNECT_ONE_SHOT を使用)。スレッドをサポートしない Web ビルドでは、スレッド化されたベイクを利用できません。

GDScript と C# のバックグラウンドスレッドでのベイクの例(2D および 3D)の全容は、references/async-baking.md を参照してください。

非同期ベイクを使用する場面: プロシージャル生成されるレベル、破壊可能な地形、または実行時にナビゲーションメッシュを再構築する必要があるシーンに適しています。メッシュのベイク中もゲームは動作し続けます。

ナビゲーションレイヤー

ナビゲーションレイヤーを使うと、さまざまなエージェントタイプ(地上部隊、飛行ユニット、大型の敵)ごとに歩行可能なエリアを分けられます。

# Assign layer bits on the NavigationRegion (Inspector or code)
# Layer 1 = ground, Layer 2 = air, Layer 3 = large

# On the NavigationAgent, set matching layers:
$NavigationAgent2D.navigation_layers = 1   # ground only
$NavigationAgent2D.navigation_layers = 2   # air only
$NavigationAgent2D.navigation_layers = 1 | 2  # both (bitwise OR)
// Assign layer bits on the NavigationRegion (Inspector or code)
// Layer 1 = ground, Layer 2 = air, Layer 3 = large

var navAgent = GetNode<NavigationAgent2D>("NavigationAgent2D");
navAgent.NavigationLayers = 1;       // ground only
navAgent.NavigationLayers = 2;       // air only
navAgent.NavigationLayers = 1 | 2;   // both (bitwise OR)

NavigationRegion と NavigationAgent の両方で navigation_layers を設定し、値を一致させてください。レイヤーの不一致は、エージェントが経路を見つけられない最も一般的な原因のひとつです。


2. NavigationAgent2D の基本的な使い方

GDScript
extends CharacterBody2D

@export var speed: float = 120.0

@onready var nav_agent: NavigationAgent2D = $NavigationAgent2D


func _ready() -> void:
	# velocity_computed fires when avoidance calculates a safe velocity
	nav_agent.velocity_computed.connect(_on_velocity_computed)


func _physics_process(delta: float) -> void:
	if nav_agent.is_navigation_finished():
		return

	var next_pos: Vector2 = nav_agent.get_next_path_position()
	var direction: Vector2 = (next_pos - global_position).normalized()
	var desired_velocity: Vector2 = direction * speed

	if nav_agent.avoidance_enabled:
		# Hand desired velocity to the avoidance system; wait for the signal
		nav_agent.velocity = desired_velocity
	else:
		velocity = desired_velocity
		move_and_slide()


func _on_velocity_computed(safe_velocity: Vector2) -> void:
	velocity = safe_velocity
	move_and_slide()


func set_target(target_pos: Vector2) -> void:
	nav_agent.target_position = target_pos

NavigationAgent2D の主なプロパティ:

プロパティ用途
target_positionワールド座標での目的地
path_desired_distanceウェイポイントに到達したと判定する距離(デフォルトは 20)
target_desired_distance最終目標に到達したと判定する距離(デフォルトは 10)
avoidance_enabledRVO 障害物回避を有効にします
radius回避判定に使用するエージェントの衝突半径
time_horizon_agents回避時に先読みする秒数(ジッターを減らすよう調整します)
C#
using Godot;

public partial class Enemy2D : CharacterBody2D
{
    [Export] public float Speed { get; set; } = 120f;

    private NavigationAgent2D _navAgent;

    public override void _Ready()
    {
        _navAgent = GetNode<NavigationAgent2D>("NavigationAgent2D");
        _navAgent.VelocityComputed += OnVelocityComputed;
    }

    public override void _PhysicsProcess(double delta)
    {
        if (_navAgent.IsNavigationFinished()) return;

        Vector2 nextPos = _navAgent.GetNextPathPosition();
        Vector2 direction = (nextPos - GlobalPosition).Normalized();
        Vector2 desiredVelocity = direction * Speed;

        if (_navAgent.AvoidanceEnabled)
            _navAgent.Velocity = desiredVelocity;
        else
        {
            Velocity = desiredVelocity;
            MoveAndSlide();
        }
    }

    private void OnVelocityComputed(Vector2 safeVelocity)
    {
        Velocity = safeVelocity;
        MoveAndSlide();
    }

    public void SetTarget(Vector2 targetPos) => _navAgent.TargetPosition = targetPos;
}

3. NavigationAgent3D の基本的な使い方

CharacterBody3D は、各物理フレームで get_next_path_position() を呼び出し、Y 軸方向を平坦化して重力を分離することで、NavigationAgent3D を動かします。avoidance_enabled が有効な場合、希望速度を nav_agent.velocity に渡し、velocity_computed ハンドラー内で移動します。無効な場合は、move_and_slide() を直接呼び出します。目的地は target_position で設定し、is_navigation_finished() で完了を確認します。

GDScript と C# による NavigationAgent3D を使った敵の例の全容は、references/navigation-agent-3d.md を参照してください。


4. ステアリング動作

ナビゲーションメッシュを使わずに自然な動きを実現する、フレームごとの軽量な計算(seek、flee、arrive、wander)です。返されたベクトルを合計して組み合わせるか、1つを選んで各 _physics_process のタイミングで velocity に設定します。

references/steering-behaviors.md で、seek、flee、arrive(減速ランプ付き)、wander(円投影によるジッター)の GDScript および C# の完全な実装を確認できます。


5. パトロールパターン

NavigationAgent2D に Marker2D のウェイポイント配列と、各ポイントで一時停止するための Timer を組み合わせることで、すっきりしたパトロールループを作成できます。wait_timer.timeout でインデックスを進め、次のウェイポイントを nav_agent.target_position に設定し、is_navigation_finished() に基づいて移動を制御します。

references/patrol-patterns.md で、ウェイポイントチェーンと待機タイマーによる一時停止を備えたパトロールの GDScript および C# の完全な実装を確認できます。


6. ビヘイビアツリーの概念

ビヘイビアツリー(BT)は、各ティックで評価されるノードのツリーです。主なノードタイプは3つあります。

タイプ成功する条件失敗する条件
Sequenceすべての子ノードが成功する(AND)いずれかの子ノードが失敗する
Selectorいずれかの子ノードが成功する(OR)すべての子ノードが失敗する
Actionリーフアクションが完了するリーフが失敗を報告する

Sequence は「Aを実行し、次にB、次にCを実行する」という処理を表します。Selector は「Aを試し、失敗したらBを試し、それも失敗したらCを試す」という処理を表します。

references/behavior-trees.md で、軽量なBTの完全な実装(BTNode基底クラスとSequence/Selector/Action)と、「追跡またはパトロール」を行う敵の実装例を、GDScriptとC#の両方で確認できます。


7. 追跡+攻撃パターン

NavigationAgent2D とステートマシンを組み合わせます。FSM の基盤については、state-machine スキルを参照してください。

ステート
ステート開始条件終了条件
PATROLデフォルト/プレイヤーが逃げたプレイヤーが detect_range に入る
CHASEプレイヤーが detect_range 内にいるプレイヤーが attack_range に入る、またはプレイヤーが逃げた
ATTACKプレイヤーが attack_range 内にいるプレイヤーが attack_range の外に出た

references/chase-attack.md で、GDScript および C# の完全な実装(PATROL → CHASE → ATTACK の遷移、攻撃クールダウンタイマー、パトロールのウェイポイントの進行、プレイヤーが逃げたときにパトロールへ戻る処理)を確認できます。

大規模なプロジェクトでは、state-machine スキルを使って各ステートを独自のノードクラスに分け、親から NavigationAgent2D の参照を渡してください。


8. 専用の2Dナビゲーションサーバー(Godot 4.5+)

Godot 4.5 より前は、NavigationServer2D は薄いフロントエンドとして、すべての処理を内部で3Dナビゲーションサーバーに委譲していました。Godot 4.5 では両者が完全に独立したサーバーに分離されました。この変更は透過的で、API の変更もコードの移行も不要ですが、実用上のメリットが2つあります。

  • 独立性: 2Dナビゲーションが3Dサーバーを経由しなくなり、2Dマップ、リージョン、エージェントは独自の実装で処理されます。
  • 2D専用ゲームのエクスポートサイズの縮小: カスタムエクスポートテンプレートは、3Dナビゲーションサーバーを含めずにコンパイルできるため(disable_navigation_3d=yes)、バイナリサイズを縮小できます。
# No code change needed — NavigationServer2D calls work identically.
# The split is internal; you continue using NavigationServer2D as before.

# Example: query a path directly via the server (unchanged API).
# Not named get_path_to: that is Node.get_path_to(node) and cannot be overridden with another signature.
func find_path_to(target: Vector2) -> PackedVector2Array:
    var map: RID = get_world_2d().get_navigation_map()
    return NavigationServer2D.map_get_path(
        map,
        global_position,
        target,
        true  # optimize path
    )
// No code change needed — NavigationServer2D calls work identically.
public Vector2[] FindPathTo(Vector2 target)
{
    Rid map = GetWorld2D().NavigationMap;
    return NavigationServer2D.MapGetPath(map, GlobalPosition, target, true);
}

2D専用のプロジェクト: 標準のエクスポートテンプレートには、引き続き3Dナビゲーションが含まれています。これを除外するには、disable_navigation_3d=yes の SCons オプションを使ってカスタムエクスポートテンプレートをコンパイルしてください(Godot 4.5+)。プロジェクト内のどこでも3Dナビゲーションノード(NavigationRegion3D、NavigationAgent3D)を使用していない場合に限り、安全に除外できます。


9. よくある落とし穴

落とし穴症状対処法
ナビゲーションメッシュがベイクされていないエージェントが動かず、経路が見つからない実行前にNavigationPolygon/NavigationMeshをベイクするか、シーンの読み込み後に実行時にbake_navigation_polygon()を呼び出します
agent_radiusが大きすぎるエージェントが出入り口や狭い通路を通れないNavigationPolygon/NavigationMeshのagent_radiusを小さくして再ベイクします。エージェント自身のradiusは回避専用であり、経路探索には影響しません
回避時のジッター他のエージェントの近くでエージェントがつまずいたり、振動したりするtime_horizon_agentsを大きくする(2~4秒を試してください)か、エージェントのmax_speedを少し下げます
経路の再計算頻度が高すぎるフレームごとにCPU負荷が急増し、エージェントの動きが遅くなるTimer(0.2~0.5秒)を追加し、毎物理フレームではなく、タイマーの発火時にのみtarget_positionを設定します
ナビゲーションレイヤーが間違っているエージェントが一部の領域を無視する、または経路が見つからないNavigationRegionとNavigationAgentのnavigation_layersビットマスクが一致していることを確認します
NavigationServerの準備が整う前にターゲットを設定している最初のフレームで経路が空になるマップは最初の物理フレームで同期されます。_ready()内で、target_positionを設定する前にawait get_tree().physics_frame(またはNavigationServer2D.map_changed)を待ちます
3Dで重力が無視されるエージェントが浮いたり、床に沈んだりする重力によるvelocity.yは常に個別に加算し、ナビゲーション方向からはX/Z成分のみをゼロにします
ベイクによってフレームレートが低下するベイクがメインスレッドで強制実行される(on_thread = false)、または非常に大きなシーンを解析しているデフォルトのスレッドベイク(bake_navigation_mesh())を維持し、bake_finishedに接続して、完了を待つために処理をブロックしないようにします

⚠️ Godot 4.7での変更点: NavigationServer3D.map_get_closest_point_normal(map, to_point)は正規化されたベクトルを返すようになりました(GH-119022)。以前は、返される面の法線が正規化されていない場合がありました。結果にnormalized()を呼び出して補正していたコードは引き続き動作しますが、正規化されていない大きさに依存していたコードは動作しなくなります。


10. チェックリスト

  • NavigationPolygon/NavigationMeshリソースを持つNavigationRegion2D/3Dをシーンに追加している
  • ナビゲーションメッシュをベイクしている(エージェントが経路を必要とする前に、エディター上または実行時に)
  • NavigationRegionとNavigationAgentのnavigation_layersビットマスクが一致している
  • NavigationAgent2D/NavigationAgent3Dが敵ノードの子になっている
  • get_target_position()ではなく、毎物理フレームget_next_path_position()を呼び出している
  • avoidance_enabledがtrueの場合に、velocity_computedシグナルを接続している
  • 目的地でのジッターを避けるため、移動前にis_navigation_finished()を確認している
  • 移動するプレイヤーを追跡する際、毎フレームではなくスロットルタイマーを使って経路のターゲットを更新している
  • agent_radiusが、レベル内で最も狭い通路を通れる大きさになっている
  • 重力を水平ナビゲーション速度とは別に適用している(3Dのみ)
  • 大規模または動的なマップでは、デフォルトのスレッドベイク(bake_navigation_mesh()、on_thread = true)を維持し、bake_finishedを待っている
  • Godot 4.5以降の2D専用プロジェクトでは、disable_navigation_3d=yesを指定してカスタムエクスポートテンプレートをビルドし、エクスポートサイズを削減できる

コメント