Godot入門:NavigationAgent3Dの使い方と活用法

はじめに

Path3DとPathFollow3Dで固定されたパスに沿った移動ができました。しかし、ゲームの多くの場面では「障害物を避けながら目標地点まで自動的に移動してほしい」という要求があります。敵AI、NPC、自動運転など、動的な経路探索が必要な場面で活躍するのがNavigationAgent3Dです。

NavigationAgent3Dを使うと、「ナビゲーションメッシュ」という事前計算された移動可能領域を利用して、複雑な障害物環境でも最適な経路を自動探索できます。敵が部屋の中を蛇行して敵に近づく、NPCが町を自由に歩き回る——こうした知的な動きを簡単に実装できます。

NavigationAgent3Dとは?

NavigationAgent3Dは、3D空間での「経路探索エージェント」です。NavigationRegion3D が定義したナビゲーションメッシュを参照し、現在位置から目標位置までの最適なパスを算出し、次に進むべき位置を教えてくれます。

継承ツリー:

NavigationAgent3D → Node → Object

重要な点として、NavigationAgent3DはNode3Dではなく単なるNodeです。そのため、キャラクターやNPCに子として追加します(親の実際の移動はCharacterBody3Dなどで処理)。

NavigationAgent3Dの主な仕組みは以下の通りです。

  • ナビゲーションメッシュ(NavMesh):NavigationRegion3Dで定義された「移動可能な領域」。障害物の周りを自動で迂回する情報を持つ
  • 経路探索(A*アルゴリズム):出発点から目標点までの最適なウェイポイント列を算出
  • ローカル回避:他のエージェントや動的障害物を避けながら移動
  • シグナルベース:目標達成やウェイポイント到達時にシグナルを発火




NavigationAgent3Dとナビゲーションメッシュ
NavigationRegion3Dが定義するNavMesh上で、複数のNavigationAgent3Dが独立した経路を探索

このノードを使うべき場面

使う場面:

  • 敵AI:障害物を避けながらプレイヤーを追跡する敵
  • NPC移動:町やダンジョンを歩き回るキャラクター
  • 自動運転:指定地点に自動で移動する乗り物やドローン
  • 群衆シミュレーション:多数のエージェントが同時に目標地点を目指す
  • タワーディフェンス:敵ユニットがマップ上のゴールまで最短経路で移動

使わない場面:

  • プレイヤー操作キャラ:プレイヤーの自由な移動にはNavigationAgent3Dは不要(単にCharacterBody3Dで十分)
  • ナビゲーションメッシュを用意できない環境:複雑に変形する環境や完全に動的な障害物ばかりの場合、NavMeshの設定・更新が煩雑

主なプロパティと機能

プロパティ 説明 デフォルト
target_position Vector3 目標位置。この位置までの経路を自動探索 Vector3.ZERO
path_desired_distance float パスに沿って生成するウェイポイント間の距離(メートル) 1.0
target_desired_distance float 目標地点と見なす許容距離 0.1
max_speed float 最大移動速度(m/s)。加速度計算に使用 0.0(無制限)
path_postprocessing int(enum) パス最適化方法(NONE / CORRIDORFUNNEL / EDGECENTROID) CORRIDORFUNNEL

主なメソッド:

# 次に進むべき位置を取得
get_next_path_position() -> Vector3

# 目標位置を設定
set_target_position(Vector3 position)

# 経路探索が完了したか確認
is_navigation_finished() -> bool

# 現在のパス(ウェイポイント列)を取得
get_current_navigation_path() -> PackedVector3Array

# 予測される衝突を事前に検知(ローカル回避)
get_avoidance_agent() -> RID

主なシグナル:

# 経路探索が完了し、目標地点に到達した
navigation_finished

# 次のウェイポイントに到達
waypoint_reached(details: Dictionary)  # details: { "index": int }

# 目標位置が設定された
target_reached

コード例1:シンプルな敵AI(目標地点を自動追跡)

extends CharacterBody3D

@export var speed = 5.0

@onready var nav_agent = $NavigationAgent3D

func _ready():
	nav_agent.target_position = Vector3(10, 0, 10)  # 目標位置を設定

func _physics_process(delta):
	# 目標位置に到達していなければ移動
	if not nav_agent.is_navigation_finished():
		var next_pos = nav_agent.get_next_path_position()
		var direction = (next_pos - global_position).normalized()

		velocity = direction * speed
		move_and_slide()
	else:
		# 到達したら停止
		velocity = Vector3.ZERO
		print("目標地点に到達しました")

コード例2:プレイヤー追跡敵(ターゲット位置の更新)

extends CharacterBody3D

@export var speed = 4.0
@export var chase_range = 20.0

var player: CharacterBody3D
var is_chasing = false

@onready var nav_agent = $NavigationAgent3D

func _ready():
	player = get_tree().get_first_child_in_group("player")

func _physics_process(delta):
	if not player:
		return

	var distance_to_player = global_position.distance_to(player.global_position)

	# プレイヤーが範囲内なら追跡開始
	if distance_to_player < chase_range:
		is_chasing = true
		nav_agent.target_position = player.global_position
	else:
		is_chasing = false

	if is_chasing and not nav_agent.is_navigation_finished():
		var next_pos = nav_agent.get_next_path_position()
		var direction = (next_pos - global_position).normalized()

		# プレイヤー方向を向く
		look_at(player.global_position, Vector3.UP)

		velocity = direction * speed
		move_and_slide()
	else:
		velocity = velocity.lerp(Vector3.ZERO, 0.1)  # スムーズに停止
		move_and_slide()

コード例3:シグナルを使った目標到達判定

extends CharacterBody3D

@onready var nav_agent = $NavigationAgent3D
var waypoints: PackedVector3Array = []
var current_waypoint_index = 0

func _ready():
	# シグナルを接続
	nav_agent.waypoint_reached.connect(_on_waypoint_reached)
	nav_agent.navigation_finished.connect(_on_navigation_finished)

	# 巡回ポイントを設定
	waypoints = [
		Vector3(0, 0, 0),
		Vector3(10, 0, 0),
		Vector3(10, 0, 10),
		Vector3(0, 0, 10),
	]

	# 最初のウェイポイントを目指す
	nav_agent.target_position = waypoints[current_waypoint_index]

func _physics_process(delta):
	if not nav_agent.is_navigation_finished():
		var next_pos = nav_agent.get_next_path_position()
		var direction = (next_pos - global_position).normalized()
		velocity = direction * 5.0
		move_and_slide()
	else:
		velocity = Vector3.ZERO

func _on_waypoint_reached(details: Dictionary):
	print("ウェイポイント", details["index"], "に到達")

func _on_navigation_finished():
	# 次のウェイポイントに目指す
	current_waypoint_index = (current_waypoint_index + 1) % waypoints.size()
	nav_agent.target_position = waypoints[current_waypoint_index]

もっと使いこなす:カスタマイズできるパラメータ

まずは基本を動かしてみてから、余裕が出たら試してみてください。

パラメータ 目的 実装例
path_desired_distanceを調整 ウェイポイント間隔を制御し、移動の滑らかさを調整 nav_agent.path_desired_distance = 0.5
小さいほど細かい経路
target_desired_distanceを拡大 到達判定の許容距離を広げる(微調整が不要な場合) nav_agent.target_desired_distance = 1.0
大型キャラは距離を広げる
max_speedを設定 AI の最大速度制限(複数敵の速度統制) nav_agent.max_speed = 5.0
path_postprocessingを変更 パス最適化の強度を調整 nav_agent.path_postprocessing = NavigationAgent3D.PATH_POSTPROCESSING_EDGECENTROID
直角を避けた移動
複数敵の同時移動 複数のエージェントが群衆シミュレーションを実現 複数のCharacterBody3D × NavigationAgent3Dを配置し、各々target_positionを設定

応用例:ナビゲーションメッシュの設定方法

# シーンに NavigationRegion3D を追加し、以下の構成にする:
# - NavigationRegion3D
#   - 静的障害物(CSGBox3D など)
#   - 通路メッシュ(MeshInstance3D など)

# NavigationRegion3D を選択状態で、
# メニュー「Navigation > Bake NavMesh」を実行して NavMesh を生成




ナビゲーションメッシュの可視化
NavigationRegion3Dが定義するNavMesh(紫色)。障害物(灰色)の周りを迂回する経路が自動生成される

まとめ

NavigationAgent3Dは「ナビゲーションメッシュを使った自動経路探索」を実現する、ゲームAI開発の必須ノードです。複雑な障害物環境でも、事前計算されたNavMeshを活用すれば、敵やNPCが知的に移動します。

  • 経路探索の自動化:目標位置を設定するだけで、最短経路が自動計算される
  • ナビゲーションメッシュが肝:NavigationRegion3Dで事前にNavMeshをベイク(計算)することが重要
  • シグナルベースの制御:waypoint_reached や navigation_finished を活用して、イベント駆動な動作を実装

次回は、3Dキャラクターアニメーションの骨格を管理する「Skeleton3D」を解説します。




群衆シミュレーション例
複数のNavigationAgent3Dが同じNavMesh上で独立した経路探索を実行。敵ユニットの群衆シミュレーション例

シリーズ:Godot 4 ノード解説

001〜040:各種ノード | 041~070:個別ノード解説

  • 041: CanvasLayer
  • 042: ParallaxLayer
  • 043: Parallax2D
  • 044: Control
  • 045: PanelContainer
  • 046: TabContainer
  • 047: MarginContainer
  • 048: AnimationPlayer
  • 049: AnimationTree
  • 050: Tween
  • 051: CPUParticles2D
  • 052: GPUParticles2D
  • 053: Sprite2D
  • 054: CharacterBody2D
  • 055: RigidBody2D
  • 056: StaticBody2D
  • 057: Area2D
  • 058: AudioStreamPlayer
  • 059: AudioStreamPlayer2D
  • 060: AudioStreamPlayer3D
  • 061: MultiMeshInstance3D
  • 062: MeshInstance3D
  • 063: CSGBox3D
  • 064: CSGMesh3D
  • 065: OmniLight3D
  • 066: GridMap
  • 067: Path3D
  • 068: PathFollow3D
  • 069: NavigationAgent3D
  • 070: Skeleton3D

この記事はGodot 4.xをもとに執筆しています。

コメント