はじめに
3Dゲームで「敵が一定のルートを巡回する」「カメラが滑らかなカーブを描いて移動する」といった要求がよくあります。単純な直線移動では単調ですし、計算で円や曲線を作るのは複雑です。そこで活躍するのがPath3Dです。
Path3Dを使うと、3D空間上にベジェ曲線(滑らかな曲線)を定義できます。この曲線に沿って敵やカメラを移動させれば、複雑な計算なしに自然な動きを実現できます。特にPathFollow3Dと組み合わせると、その威力が引き出されます。
Path3Dとは?
Path3Dは、3D空間上に「ベジェ曲線パス」を定義するノードです。複数のコントロールポイントをハンドルで結んで、滑らかなパスを作ります。
継承ツリー:
Path3D → Node3D → Node → Object
Path3Dの核は、内部のCurve3Dリソースです。これが実際のパスの形状を保持し、ポイント・ハンドル・パラメータを管理します。
Path3Dの主な特徴は以下の通りです。
- ベジェ曲線で滑らかなパスを作成:2次元のTileMapにおけるパスとは異なり、3Dの任意の位置・方向をサポート
- バリング(tilt)対応:パス上で回転(ねじり)を定義でき、カメラレールやローラーコースターに最適
- エディタでの直感的編集:3Dビューポート上でハンドルをドラッグしてパスを編集
- Curve3Dの豊富なメソッド:サンプリング・長さ計算・最近接ポイント検索など、スクリプト制御も容易

このノードを使うべき場面
使う場面:
- 巡回する敵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) |
応用例:カメラが複雑な軌道を描くカットシーン
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)

まとめ
Path3Dは「3D空間上のベジェ曲線パス」を定義し、敵の巡回ルート・カメラレール・乗り物の軌道などに使用する強力なツールです。内部のCurve3Dリソースが曲線の計算を担当し、スクリプトでの制御も容易です。
- 直感的な編集:エディタ上でハンドルをドラッグしてパスを作成
- PathFollow3Dとの組み合わせ:次回解説するPathFollow3Dと一緒に使うことで、パスに沿った移動を簡単に実装
- 高度なカスタマイズ:Tiltやハンドル制御で、複雑な3D動作も表現可能
次回は、Path3D上を移動するための専用ノード「PathFollow3D」を解説します。

シリーズ: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をもとに執筆しています。


コメント