背後から敵の足音が近づいてくる。遠くの爆発が小さく左から聞こえる。洞窟に入った瞬間、音に残響がかかる——3Dゲームの没入感は、こうした 「音がどこから、どれくらいの距離で鳴っているか」 の表現で大きく変わります。
Godotではこれを AudioStreamPlayer3D が引き受けてくれます。音源に位置を持たせるだけで、リスナー(通常はカメラ)との距離と方向に応じて、音量とステレオの左右(パン)が自動で変わります。この記事では、その基本設定から減衰モデルの選び方、リスナーの分離、ドップラー効果、エリアごとの残響までを組み立てます。
この記事でわかること
AudioStreamPlayer3Dの基本—— 距離で音量、方向でパンが自動変化- シーン規模で選ぶ 減衰モデル(Inverse / Square / Log / Disabled)
AudioListener3Dで カメラとリスナーを分離 する(TPS・カットシーン)- ドップラー効果 と Area3Dのリバーブゾーン
- 距離で こもらせる フィルタと、大量音源の パフォーマンス最適化
AudioStreamPlayer3Dの基本
AudioStreamPlayer3D は、 3D空間内で位置を持つ 音声再生ノードです。リスナー(通常は current = true のCamera3D)との 距離 に応じて音量が、 方向 に応じてステレオの左右(パン)が自動で変わります。「右奥から敵の声」「真後ろで爆発」といった定位が、位置を置くだけで作れます。

音の届き方を決める主要プロパティはこのあたりです。
| プロパティ | 説明 | 既定値 |
|---|---|---|
unit_size | 音量が半分になる距離。 実質の"聞こえる範囲"を決める | 10.0 |
max_distance | これより遠いと完全に無音になる距離(0=無制限) | 0 |
attenuation_model | 距離による減衰の計算方式(後述) | Inverse Distance |
panning_strength | 左右パンの強さ | 1.0 |
emission_angle_enabled | 指向性(特定方向へ強く飛ばす) | false |
敵の足音を鳴らす基本形はこうです。
# Enemy (CharacterBody3D)
# └── FootstepSound (AudioStreamPlayer3D)
@onready var footstep: AudioStreamPlayer3D = $FootstepSound
func _ready() -> void:
footstep.stream = preload("res://audio/sfx/footstep.ogg")
footstep.unit_size = 5.0 # 5mで音量が半分=そこそこ近くでよく聞こえる
footstep.max_distance = 30.0 # 30mより遠いと無音(無駄な計算を切る)
footstep.bus = "SFX" # SFXバスに通す
func play_footstep() -> void:
if not footstep.playing: # 多重再生を避ける
footstep.play()
unit_size が「聞こえる範囲」の体感を決めるつまみです。 監視カメラの警告音やスピーカー放送のように「特定方向にだけ飛ばしたい」 ときは、emission_angle_enabled = true にして emission_angle_degrees で角度を絞ります。
減衰モデルの選択
attenuation_model は、 距離が離れるにつれ音量がどんな曲線で下がるか を決めます。リアルさを取るか、ゲームの聞き取りやすさを取るかで選びます。

| モデル | 減衰 | 向いているシーン |
|---|---|---|
| Inverse Distance | 距離に反比例(緩やか) | 屋外の広いフィールド |
| Inverse Square | 距離の2乗に反比例(現実的で急) | リアル志向のゲーム |
| Logarithmic | 対数的(人間の聴覚に近い) | 室内・近距離のやり取り |
| Disabled | 減衰なし(一定) | BGM的な環境音・アンビエント |
footstep.attenuation_model = AudioStreamPlayer3D.ATTENUATION_INVERSE_SQUARE_DISTANCE
# unit_size と max_distance の目安(シーン規模ごと)
# 小さい部屋 : unit_size=2.0, max_distance=10.0
# 中規模屋内 : unit_size=5.0, max_distance=25.0
# 屋外フィールド: unit_size=10.0, max_distance=50.0
迷ったら Inverse Square(現実的) を基準に、聞こえづらければ unit_size を大きくして調整するのが手堅い進め方です。
AudioListener3Dでリスナーを分離する
既定では「カメラのいる場所」で音を聴きます。ところが 三人称視点(TPS)でカメラを大きく引く と、カメラ位置とプレイヤー位置がずれ、「自分のすぐ横の物音が遠く聞こえる」違和感が生まれます。
そこで AudioListener3D を プレイヤーの子 に置いて有効化すると、カメラがどこにあっても プレイヤーの位置を基準に 音が聴こえるようになります。

| パターン | リスナー | 用途 |
|---|---|---|
| 一般的なゲーム | Camera3D(既定) | カメラ位置=聴取位置でよい |
| TPS(三人称) | AudioListener3D | 引いたカメラでもプレイヤー付近の音を聴かせる |
| カットシーン | AudioListener3D | カメラが動いてもプレイヤー基準を保つ |
# Player (CharacterBody3D)
# └── AudioListener3D
@onready var listener: AudioListener3D = $AudioListener3D
func _ready() -> void:
listener.make_current() # このリスナーを有効化(カメラより優先される)
make_current() を呼んだ瞬間から、聴取点がここに移ります。カットシーンだけ一時的にカメラへ戻したいなら clear_current() で解除できます。
ドップラー効果
すれ違う車、通り過ぎる救急車——動く音源が近づくと音程が上がり、遠ざかると下がる。この ドップラー効果 も、プロパティ1つで有効化できます。

# 音源とリスナー(Camera3D)の両方でドップラー追跡を有効にする
$AudioStreamPlayer3D.doppler_tracking = AudioStreamPlayer3D.DOPPLER_TRACKING_PHYSICS_STEP
# トラッキングモード
# DOPPLER_TRACKING_DISABLED … 無効(既定)
# DOPPLER_TRACKING_IDLE_STEP … _process()に同期
# DOPPLER_TRACKING_PHYSICS_STEP … _physics_process()に同期(高速移動でも安定)
ドップラーは 音源の速度から計算 されるため、高速に動くオブジェクトでは物理と同期する PHYSICS_STEP が安定します(_processと_physics_processの使い分け も参考に)。使いどころはレースゲーム・弾丸・乗り物などに絞るのがおすすめです。常時オンだと計算が増えます。
Area3Dのリバーブゾーン
「洞窟に入った瞬間、音が反響する」——空間ごとの残響は、Area3D の リバーブゾーン 機能で自動化できます。AudioBusエフェクト の記事では手動でリバーブを付け外ししましたが、こちらは エリアに入ったら自動で 専用バスへ切り替わる仕組みです。

Area3D に CollisionShape3D で範囲を作り、リバーブ用バスを指定します。
func setup_reverb_zone() -> void:
var area := $ReverbZone as Area3D
area.reverb_bus_enabled = true # このエリアのリバーブを有効化
area.reverb_bus_name = &"CaveReverb" # 送り先のリバーブバス
area.reverb_bus_amount = 0.6 # どれだけリバーブ側へ送るか
area.reverb_bus_uniformity = 0.8 # エリア内でのかかり方の均一さ
送り先の CaveReverb バスには、あらかじめ AudioEffectReverb(room_size: 0.85 / wet: 0.4 など)を追加しておきます。プレイヤーが範囲に入ると、 範囲内の音が自動でこのバスへ送られ、残響がかかります。エリアを出れば自動で戻る——出入りのコードを書かずに済むのが利点です。
距離でこもらせる+パフォーマンス
さらにリアルにするなら、 遠くの音の高音を削って「こもらせる」 と距離感が増します。近い音はクリアに、遠い音はモゴモゴと——これはローパスフィルタ用のプロパティで作れます。

extends AudioStreamPlayer3D
@export var listener_node: Node3D
@export var far_distance: float = 30.0
func _process(_delta: float) -> void:
if not listener_node:
return
var dist := global_position.distance_to(listener_node.global_position)
var ratio := clampf(dist / far_distance, 0.0, 1.0)
# 遠いほど高音の上限を下げる(20500Hz→2000Hz)=こもる
attenuation_filter_cutoff_hz = lerpf(20500.0, 2000.0, ratio)
パフォーマンス最適化
オープンワールドのように音源が大量にあると、CPU負荷が問題になります。効くのはこの3つです。
| 対策 | 説明 |
|---|---|
max_distance を必ず設定 | 0(無制限)を避け、必要な範囲だけ計算させる |
| 同時再生数を絞る | max_polyphony を1〜4に、同時に鳴るノードは20〜30以下を目安に |
| 遠い音源は止める | リスナーから十分離れたら playing = false で停止(LOD的な間引き) |
# リスナーから遠く離れた音源は停止してCPUを節約
func _process(_delta: float) -> void:
var camera := get_viewport().get_camera_3d()
if not camera:
return
var dist := global_position.distance_to(camera.global_position)
if dist > max_distance * 1.2 and playing:
stop()
elif dist <= max_distance and not playing:
play()
大量の音源を オブジェクトプーリング 的に管理する発想も、負荷が増えてきたら有効です。
おまけ:先に知っておくと良いこと
- まずは
unit_sizeで調整 :思ったより聞こえない・聞こえすぎるときは、減衰モデルをいじる前にunit_sizeを上下させるのが手っ取り早いです。 - 2Dゲームなら AudioStreamPlayer2D :見下ろし2Dでも「音源からの距離・左右」は表現できます。3Dの考え方はほぼそのまま2Dにも通じます。
- 環境音は場所ごとにアンビエントを :滝・焚き火・雑踏などは、音源を置いて
Disabled減衰+短いmax_distanceにすると「そこに近づくと聞こえる」環境音になります。 - 曲の切り替えはアダプティブミュージックへ :エリアや戦況でBGMを変える演出は アダプティブミュージック の領域です。
まとめ
AudioStreamPlayer3Dは距離で音量、方向でパンが自動変化。unit_sizeが聞こえる範囲の体感を決める- 減衰モデル はシーン規模で選ぶ(迷ったらInverse Square)。
max_distanceは必ず設定して無駄な計算を切る AudioListener3Dでカメラと聴取点を分離できる(TPS・カットシーンで有効)- ドップラー は
doppler_trackingをPHYSICS_STEPに、Area3D はリバーブゾーンで空間ごとの残響を自動化 - 最適化 は
max_distance・同時再生数・遠距離の停止が三本柱
まずは敵に AudioStreamPlayer3D で足音を付け、unit_size と max_distance をいじって「近づくと聞こえる」感覚を確かめてみてください。そこにリスナー分離やエリアリバーブを足すと、世界がぐっと立体的に鳴りだします。
さらに学ぶために
- オーディオ管理の基礎(AudioStreamPlayerとAudio Bus) ——2D/3D共通の土台とバス構成
- AudioBusエフェクトでサウンドデザイン ——リバーブバスなどエフ ェクトの作り込み
- アダプティブミュージック ——場面に応じてBGMを動的に変える
- _processと_physics_processの使い分け ——ドップラーの
PHYSICS_STEPを理解する土台 - Godot公式ドキュメント:AudioStreamPlayer3D ——プロパティの一次情報