導入: なぜゲームAIにパスファインディングが必要なのか
ゲーム開発において、敵キャラクターやNPCの 移動 は、プレイヤー体験の質を大きく左右する要素です。壁や障害物、入り組んだマップが存在する場合、AIは目的地までの 最適な経路 を見つけ出す必要があります。この「最適な経路を見つけ出す」技術こそが パスファインディング です。
Godot Engineでは、この複雑なパスファインディング処理を簡単かつ効率的に実現するために、 NavigationAgent2D ノードを提供しています。
主要な概念とNavigationAgent2Dの役割
Godotのナビゲーションシステムは、主に3つの要素で構成されています。
| 要素 | ノード名 | 役割 |
|---|---|---|
| ナビゲーションマップ | NavigationServer2D | 移動可能な領域全体を管理するサーバー。 |
| 移動可能領域 | NavigationRegion2D | 実際にAIが移動できるマップ上の領域を定義する。 |
| 経路エージェント | NavigationAgent2D | 経路計算を要求し、親ノード(AIキャラクター)の移動を制御する。 |
セットアップの基本
NavigationAgent2D を機能させるには、まずマップ上に 移動可能な領域 を定義する必要があります。
NavigationRegion2Dの配置: シーンツリーにNavigationRegion2Dノードを追加します。NavigationPolygonの作成:NavigationRegion2Dのインスペクターで、新しいNavigationPolygonリソースを作成し、マップの移動可能な部分 をカバーするように編集します。- 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 を即座にゲームに組み込むことができます。