ゲーム開発において、NPCがマップ内の障害物を避けながら目的地へ移動する「賢いAI移動」は、プレイヤーの体験を大きく向上させます。Godot Engineでは、この経路探索と障害物回避を NavigationRegion2D ノードと ナビゲーションメッシュ が担っています。
本記事では、これらのノードの役割と、それらを活用してキャラクターが障害物を避けてスムーズに移動する仕組みを、具体的なコード例とともに解説します。
なぜナビゲーションメッシュが必要なのか
キャラクターの移動に ナビゲーションメッシュ が必要なのは、従来の物理ベースの移動では、キャラクターが障害物に衝突するまでその存在を知ることができないためです。
- 物理ベースの移動(Collision-based): キャラクターは、実際に障害物(
StaticBody2Dなど)に衝突して初めてその存在を認識します。これは「行き止まりにぶつかってから別の道を探す」ようなもので、非効率で不自然な動きになりがちです。 - ナビゲーションメッシュ(Path-based): 事前に「移動可能な領域」をポリゴンメッシュとして定義しておきます。AIはこの地図を参照し、衝突する前に障害物を避ける最適な経路を計算できます。
NavigationRegion2Dは、この「AI用の地図」を管理し、シーン空間に配置する役割を担うノードです。
NavigationRegion2Dによるナビゲーションメッシュの生成(ベイク)
ナビゲーションメッシュを生成するプロセスを「ベイク(Bake)」と呼びます。Godotでは、シーンに配置されたコリジョンを持つノードの形状を元に、移動可能な領域を自動で計算できます。
シーンの準備
まず、TileMapやStaticBody2Dなど、CollisionShape2DまたはCollisionPolygon2Dを持つノードでステージを構成します。これらがナビゲーションメッシュの「障害物」となります。
NavigationRegion2Dのセットアップ
NavigationRegion2Dノードをシーンに追加し、インスペクターで以下の主要プロパティを設定します。
| プロパティ名 | 説明 | 推奨値のヒント |
|---|---|---|
navigation_polygon | ナビゲーションメッシュのデータを保持するNavigationPolygonリソース。 | 「New NavigationPolygon」で新規作成します。 |
enabled | trueにすると、このリージョンがナビゲーションサーバーで有効になります。 | デフォルトでtrue。 |
source_geometry_mode | メッシュ生成の元となるジオメトリの取得方法。 | TileMapの場合はSOURCE_GEOMETRY_GROUPS_WITH_CHILDRENを使い、TileMapをナビゲーショングループに追加します。 |
NavigationPolygonリソース側で設定する重要なプロパティ:
| プロパティ名 | 説明 | 推奨値のヒント |
|---|---|---|
agent_radius | 移動するエージェントの半径。壁や障害物から安全な距離を保った経路が生成されます。 | キャラクターのコリジョン半径より少し大きめに設定します。 |
メッシュのベイク
設定が完了したら、NavigationRegion2Dノードを選択した状態で、エディタ上部のツールバーに表示される「Bake NavigationMesh」ボタンをクリックします。成功すると、シーンビューに青い半透明のポリゴンが表示されます。これがAIが移動できるエリアです。
NavigationAgent2Dによる実践的な移動スクリプト
ナビゲーションメッシュが完成したら、次はその上を移動するキャラクターを実装します。ここで中心的な役割を果たすのがNavigationAgent2Dノードです。
NavigationAgent2Dは、移動したいキャラクター(例: CharacterBody2D)の子ノードとして追加します。このエージェントが、ナビゲーションサーバーと通 信し、経路の計算や他のエージェントとの衝突回避を行います。
拡張された移動スクリプト
以下のスクリプトは、マウスカーソルをクリックした位置にキャラクターを移動させる実践的な例です。
# CharacterBody2Dにアタッチするスクリプト
extends CharacterBody2D
@export var speed: float = 200.0
@onready var navigation_agent: NavigationAgent2D = $NavigationAgent2D
func _ready() -> void:
# エージェントのプロパティを設定
navigation_agent.path_desired_distance = 4.0
navigation_agent.target_desired_distance = 4.0
func _physics_process(delta: float) -> void:
if navigation_agent.is_navigation_finished():
return
# 現在のターゲット位置を取得
var current_agent_target: Vector2 = navigation_agent.get_next_path_position()
# 移動方向を計算
var new_velocity: Vector2 = (current_agent_target - global_position).normalized() * speed
# RVO(相互速度障害物法)による衝突回避を適用
# set_velocity()を呼ぶと、velocity_computedシグナルで安全な速度が返される
navigation_agent.set_velocity(new_velocity)
func _input(event: InputEvent) -> void:
if event.is_action_pressed("click"):
# マウスクリック位置をターゲットに設定
navigation_agent.target_position = get_global_mouse_position()
func _on_navigation_agent_2d_velocity_computed(safe_velocity: Vector2) -> void:
# シグナルハンドラ内でのみmove_and_slide()を呼ぶ
# (_physics_processとの二重呼び出しを避ける)
velocity = safe_velocity
move_and_slide()
経路探索とRVO回避
NavigationAgent2D は、以下の二つの主要な役割を果たします。
- 経路探索:
get_next_path_position()で次の移動ポイントを提供し、キャラクターは静的な障害物を避けることができます。 - RVO回避:
velocity_computedシグナルを利用して、RVO(Reciprocal Velocity Obstacles) に基づき、他の動くエージェントとの衝突を避けるために調整された速度ベクトルを取得できます。
動的な障害物への対応
ゲーム中に動的に出現する障害物(例: プレイヤーが設置したオブジェクト)を避けさせたい場合は、その障害物に NavigationObstacle2D ノードを追加します。
NavigationObstacle2D は、メッシュを再ベイクすることなく、その周囲に一時的な「回避領域」を設定します。これにより、 NavigationAgent2D を持つ他のエージェントは、この動的な障害物を避けるように動作を調整します。
よくある間違いとベストプラクティス
| よくある間違い | ベストプラクティス |
|---|---|
_physics_process内で毎フレームtarget_positionを設定している。 | target_positionは、目的地が変更されたとき(例: マウスクリック時)に一度だけ設定します。毎フレーム設定すると、経路計算が繰り返し発生し、パフォーマンスが低下します。 |
get_next_path_position()の結果をそのままglobal_positionに設定している。 | テレポートのような不自然な動きになります。get_next_path_position()はあくまで「次の中継点」です。キャラクターは現在位置からその中継点に向かって移動させるべきです。 |
| RVO回避が機能しない(キャラクターが重なる)。 | NavigationAgent2Dのvelocity_computedシグナルを使い、計算されたsafe_velocityをCharacterBody2Dのvelocityに設定するのが最も確実です。 |
| 動的障害物を避けない。 | NavigationObstacle2Dが有効になっているか、また障害物のコリジョンレイヤーとエージェントのコリジョンマスクが適切に設定されているか確認してください。 |
まとめ
NavigationRegion2D とナビゲーションメッシュは、Godot Engineで賢いAI移動を実現するための基本要素です。
| 要素 | 役割 | 避ける対象 |
|---|---|---|
NavigationRegion2D | 移動可能領域(ナビゲーションメッシュ)の定義と保持 | 静的な壁や地形 |
NavigationAgent2D | 経 路探索の実行と移動の調整 | 他の動くエージェント、 NavigationObstacle2D |
このシステムを理解し活用することで、ゲームのNPCは、マップの構造を理解し、他のキャラクターと協調しながら、賢く目的地へとたどり着くことができるでしょう。