【Godot】NavigationAgent2Dによるパスファインディング - 敵AIの追跡と巡回

作成: 2025-12-08

Godot EngineのNavigationAgent2Dノードを使用して、効率的かつ自然な敵AIの追跡・巡回動作を実装する方法を解説します。

導入: なぜゲームAIにパスファインディングが必要なのか

ゲーム開発において、敵キャラクターやNPCの 移動 は、プレイヤー体験の質を大きく左右する要素です。壁や障害物、入り組んだマップが存在する場合、AIは目的地までの 最適な経路 を見つけ出す必要があります。この「最適な経路を見つけ出す」技術こそが パスファインディング です。

Godot Engineでは、この複雑なパスファインディング処理を簡単かつ効率的に実現するために、 NavigationAgent2D ノードを提供しています。

主要な概念とNavigationAgent2Dの役割

Godotのナビゲーションシステムは、主に3つの要素で構成されています。

要素ノード名役割
ナビゲーションマップNavigationServer2D移動可能な領域全体を管理するサーバー。
移動可能領域NavigationRegion2D実際にAIが移動できるマップ上の領域を定義する。
経路エージェントNavigationAgent2D経路計算を要求し、親ノード(AIキャラクター)の移動を制御する。

セットアップの基本

NavigationAgent2D を機能させるには、まずマップ上に 移動可能な領域 を定義する必要があります。

  1. NavigationRegion2Dの配置: シーンツリーに NavigationRegion2D ノードを追加します。
  2. NavigationPolygonの作成: NavigationRegion2D のインスペクターで、新しい NavigationPolygon リソースを作成し、マップの移動可能な部分をカバーするように編集します。
  3. AIキャラクターの準備: 敵AIのルートノード(例: CharacterBody2D)の子として NavigationAgent2D ノードを追加します。

実践例1: 敵AIによるプレイヤー追跡

敵AIがプレイヤーを追跡するロジックは、パスファインディングの最も基本的なユースケースです。

追跡ロジックの実装

# Enemy.gd (CharacterBody2Dにアタッチ)

extends CharacterBody2D

@export var speed = 200.0
@onready var navigation_agent = $NavigationAgent2D

var target_position = Vector2.ZERO

func _ready():
    navigation_agent.max_speed = speed

func set_target(new_target_position: Vector2):
    target_position = new_target_position
    navigation_agent.target_position = target_position

func _physics_process(delta):
    if navigation_agent.is_navigation_finished():
        velocity = Vector2.ZERO
        move_and_slide()
        return

    var next_path_position = navigation_agent.get_next_path_position()
    var direction = global_position.direction_to(next_path_position)

    velocity = direction * speed
    move_and_slide()

このコードでは、 set_target() で目標を設定すると、 NavigationAgent2D が自動的に経路を計算します。 _physics_process では、 get_next_path_position() で得られた位置に向かってキャラクターを動かすだけで、障害物を避けた移動が実現します。

実践例2: 自然な巡回(パトロール)の実装

敵AIに複数のポイントを順番に巡回させるパトロール動作も、 NavigationAgent2D を使えば容易に実装できます。

巡回ロジックの実装

# PatrolEnemy.gd (CharacterBody2Dにアタッチ)

extends CharacterBody2D

@export var speed = 150.0
@onready var navigation_agent = $NavigationAgent2D

var patrol_points = [Vector2(100, 100), Vector2(500, 100), Vector2(500, 500), Vector2(100, 500)]
var current_point_index = 0

func _ready():
    navigation_agent.max_speed = speed
    _set_next_patrol_point()

func _set_next_patrol_point():
    var next_point = patrol_points[current_point_index]
    navigation_agent.target_position = next_point

func _physics_process(delta):
    if navigation_agent.is_navigation_finished():
        current_point_index = (current_point_index + 1) % patrol_points.size()
        _set_next_patrol_point()

    var next_path_position = navigation_agent.get_next_path_position()
    var direction = global_position.direction_to(next_path_position)

    velocity = direction * speed
    move_and_slide()

この実装の鍵は、 navigation_agent.is_navigation_finished() の利用です。このメソッドは、エージェントが目標地点に到達したと判断したときに true を返すため、手動で距離を計算して判定するよりも正確で信頼性の高い目標到達判定が可能です。

実装のベストプラクティス

1. 経路再計算の頻度を制御する

navigation_agent.target_position を設定するたびに、経路の再計算が行われます。プレイヤー追跡AIの場合、毎フレーム目標を更新するとパフォーマンスに影響を与える可能性があります。

  • タイマーの使用: 0.1秒ごとなど、一定の間隔で目標位置を更新するタイマーノードを使用します。
  • 距離による判定: プレイヤーが一定距離以上移動した場合にのみ、目標位置を更新します。

2. 移動の滑らかさを追求する

NavigationAgent2D は経路上の次のポイントを教えてくれますが、そのポイントに向かってキャラクターを動かすのは開発者の役割です。

単純に次のポイントに向かって移動するだけでなく、 velocity を徐々に変化させることで、より 滑らかな動き を実現できます。

3. get_next_path_position()の活用

NavigationAgent2D は、目標地点までの完全な経路を計算しますが、キャラクターが移動すべきなのは、その経路上の 次のポイント です。 get_next_path_position() は、キャラクターが現在いる位置から最も近い、経路上の次のポイントを返します。

まとめ

Godot Engineの NavigationAgent2D は、2DゲームにおけるAIの移動ロジックを劇的に簡素化する強力なツールです。

  • NavigationRegion2D で移動可能領域を定義し、
  • NavigationAgent2D に目標位置を設定し、
  • get_next_path_position() で得られた次のポイントに向かってキャラクターを移動させる

というシンプルな手順で、障害物を賢く回避し、プレイヤーを追跡したり、決められたルートを巡回したりする、 実践的で自然なAI を即座にゲームに組み込むことができます。