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

はじめに

3Dゲームで「敵が一定のルートを巡回する」「カメラが滑らかなカーブを描いて移動する」といった要求がよくあります。単純な直線移動では単調ですし、計算で円や曲線を作るのは複雑です。そこで活躍するのがPath3Dです。

Path3Dを使うと、3D空間上にベジェ曲線(滑らかな曲線)を定義できます。この曲線に沿って敵やカメラを移動させれば、複雑な計算なしに自然な動きを実現できます。特にPathFollow3Dと組み合わせると、その威力が引き出されます。

Path3Dとは?

Path3Dは、3D空間上に「ベジェ曲線パス」を定義するノードです。複数のコントロールポイントをハンドルで結んで、滑らかなパスを作ります。

継承ツリー:

Path3D → Node3D → Node → Object

Path3Dの核は、内部のCurve3Dリソースです。これが実際のパスの形状を保持し、ポイント・ハンドル・パラメータを管理します。

Path3Dの主な特徴は以下の通りです。

  • ベジェ曲線で滑らかなパスを作成:2次元のTileMapにおけるパスとは異なり、3Dの任意の位置・方向をサポート
  • バリング(tilt)対応:パス上で回転(ねじり)を定義でき、カメラレールやローラーコースターに最適
  • エディタでの直感的編集:3Dビューポート上でハンドルをドラッグしてパスを編集
  • Curve3Dの豊富なメソッド:サンプリング・長さ計算・最近接ポイント検索など、スクリプト制御も容易




Path3Dの制御ポイントと曲線
Path3Dのベジェ曲線。複数のポイントとハンドルで滑らかなパスを定義

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

使う場面:

  • 巡回する敵AI:決まったルートを何度も移動する敵(パトロール敵など)
  • カメラレール:ゲーム内ムービーやカットシーンでカメラが曲線的に移動
  • ローラーコースター:プレイヤーが乗る乗り物がパスに沿って走行
  • 弾や魔法の軌道:放物線や曲線を描いて飛ぶ弾のエフェクト
  • チュートリアル誘導:プレイヤーをパスに沿ったカメラでガイド

使わない場面:

  • プレイヤーが自由に移動するゲーム:Path3Dは事前に定義されたパスなので、プレイヤーの自由な移動には向きません
  • 動的にパスを生成・変更:複雑な動的経路探索が必要な場合はNavigationAgent3Dを使う方が適切です

主なプロパティと機能

プロパティ 説明 デフォルト
curve Curve3D パスの形状を保持するリソース。ポイント・ハンドル・バリングを管理 (新規Path3D時に自動生成)

Curve3Dの主要メソッド:

# ポイントを追加(ハンドルは自動計算 or 手動で指定可能)
add_point(Vector3 position, Vector3 in = Vector3.ZERO, Vector3 out = Vector3.ZERO, Tilt tilt = 0.0)

# ポイント数を取得
get_point_count() -> int

# 指定インデックスのポイントを取得
get_point_position(int idx) -> Vector3

# パス上の距離 t(0.0〜パス総長) でのポイントをサンプリング
sample(float offset) -> Vector3

# オフセット距離のパスに沿った回転(バリング含む)を取得
sample_baked_with_rotation(float offset) -> Transform3D

# パスの総長を取得
get_baked_length() -> float

# 指定ポイントに最も近いオフセット距離を取得
get_closest_offset(Vector3 to_point) -> float

コード例1:Path3D上をPathFollow3Dで移動する敵NPC(基本)

extends Path3D

@export var patrol_speed = 2.0  # ユニット/秒

@onready var enemy = $Enemy  # 子ノードのEnemy
@onready var path_follow = $PathFollow3D  # 子ノードのPathFollow3D

func _ready():
	# pathを初期化(または手動でポイントを追加)
	if curve.get_point_count() == 0:
		# エディタで設定していない場合、パスを作成
		curve.add_point(Vector3(0, 0, 0))
		curve.add_point(Vector3(5, 0, 0))
		curve.add_point(Vector3(5, 0, 5))
		curve.add_point(Vector3(0, 0, 5))

func _physics_process(delta):
	# PathFollow3Dのprogress(距離)を増加させてパスに沿わせる
	path_follow.progress += patrol_speed * delta

	# パスの終端に達したらループ(0に戻す)
	if path_follow.progress >= curve.get_baked_length():
		path_follow.progress = 0.0

コード例2:パスをスクリプトで生成し、複数のポイントでイベント実行

extends Path3D

@onready var curve = $Curve3D

func _ready():
	generate_spiral_path(5, 10)  # 5周、高さ10
	setup_waypoint_events()

func generate_spiral_path(loops: int, height: float):
	var points = 20
	var radius = 3.0

	for i in range(points * loops):
		var angle = (float(i) / points) * TAU  # TAU = 2π
		var t = float(i) / (points * loops)

		var x = radius * cos(angle)
		var z = radius * sin(angle)
		var y = t * height

		curve.add_point(Vector3(x, y, z))

func setup_waypoint_events():
	# パスの特定位置(例:25%、50%、75%)でイベント発火
	var total_length = curve.get_baked_length()
	for progress_ratio in [0.25, 0.5, 0.75]:
		var offset = progress_ratio * total_length
		var pos = curve.sample_baked(offset)
		print("Waypoint at ", pos)

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

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

パラメータ 目的 実装例
Curve3Dのbaked_interval パスのベイク精度を調整(小さいほど高精度だが負荷増) curve.baked_interval = 0.1
高品質なカメラムービーなら小さめに
ハンドルの手動制御 ベジェ曲線のカーブを細かく調整 curve.set_point_in(idx, Vector3(1, 0, 0))
curve.set_point_out(idx, Vector3(2, 0, 0))
Tilt(バリング)の設定 パス上で回転角度を定義(ローラーコースターに最適) curve.set_point_tilt(idx, PI / 4) # 45度傾ける
sample_baked_with_rotation()の活用 パスの方向に沿った回転を自動で適用 var t3d = curve.sample_baked_with_rotation(offset)
entity.global_transform = t3d

応用例:カメラが複雑な軌道を描くカットシーン

extends Path3D

@onready var camera = get_viewport().get_camera_3d()
@export var camera_speed = 3.0
@export var look_ahead_distance = 2.0

var playback_progress = 0.0
var is_playing = false

func start_cinematic():
	is_playing = true
	playback_progress = 0.0

func _physics_process(delta):
	if not is_playing:
		return

	playback_progress += camera_speed * delta
	var curve_length = curve.get_baked_length()

	if playback_progress >= curve_length:
		is_playing = false
		return

	# カメラ位置をパスに沿わせる
	var camera_pos = curve.sample_baked(playback_progress)
	camera.global_position = camera_pos

	# 先読みポイントを見つめる(視点方向を設定)
	var look_at_progress = min(playback_progress + look_ahead_distance, curve_length)
	var look_at_pos = curve.sample_baked(look_at_progress)
	camera.look_at(look_at_pos, Vector3.UP)




Godotエディタでの Path3D編集
エディタUIでのPath3D編集。ポイントをドラッグしてハンドルを調整、滑らかな曲線を作成

まとめ

Path3Dは「3D空間上のベジェ曲線パス」を定義し、敵の巡回ルート・カメラレール・乗り物の軌道などに使用する強力なツールです。内部のCurve3Dリソースが曲線の計算を担当し、スクリプトでの制御も容易です。

  • 直感的な編集:エディタ上でハンドルをドラッグしてパスを作成
  • PathFollow3Dとの組み合わせ:次回解説するPathFollow3Dと一緒に使うことで、パスに沿った移動を簡単に実装
  • 高度なカスタマイズ:Tiltやハンドル制御で、複雑な3D動作も表現可能

次回は、Path3D上を移動するための専用ノード「PathFollow3D」を解説します。




複数のPath3Dの活用例
複数のPath3Dを同時に使用する例。敵の巡回、カメラ移動、エフェクト軌道を別々のパスで定義

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

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

  • 041: CanvasLayer
  • 042: ParallexLayer
  • 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をもとに執筆しています。

コメント