概要
ゲーム開発において、サウンドはプレイヤーの体験を大きく左右する重要な要素です。Godot EngineでBGMや効果音(SE)を扱う際、「音が途切れる」「音量調整が面倒」といった課題に直面することがあります。
この記事では、Godotのオーディオ管理の核となる AudioStreamPlayer と Audio Bus の基本から、シングルトンによる実践的な管理方法まで解説します。
Godotオーディオシステムの三大要素
| 要素 | 役割 | アナロジー |
|---|---|---|
| AudioStream | 音声データそのもの | CDやMP3ファイル |
| AudioStreamPlayer | 音を再生するノード | CDプレイヤー |
| Audio Bus | 音の信号を束ねて制御する経路 | ミキシングコンソール |
AudioStreamPlayerの種類
| ノード名 | 主な用途 | 特徴 |
|---|---|---|
AudioStreamPlayer | BGMやUI音など | 位置情報なし 、常に中央から聞こえる |
AudioStreamPlayer2D | 2Dゲームの効果音 | カメラからの距離や方向で音量・パンが変化 |
AudioStreamPlayer3D | 3Dゲームの効果音 | 3D空間での距離減衰・ドップラー効果対応 |
Audio Bus(オーディオバス)
Audio Busは、再生される音の「通り道」であり、ミキシングコンソールのような役割を持ちます。
- Master Bus: 全ての音が最終的に通る出力バス
- カスタムバス: BGM、SE、ボイスなど、種類ごとに作成
主な役割:
- 音量の一括制御: バス単位でBGM全体、SE全体の音量を調整
- エフェクトの適用: リバーブやコンプレッサーを一括適用
よくある間違いとベストプラクティス
| よくある間違い | ベストプラクティス |
|---|---|
| SE再生に単一ノードを使い回す 音が途切れる | SE再生ごとにノードを動的生成finishedシグナルでqueue_free()して破棄。またはmax_polyphonyプロパティで同一ノードでの重複再生を許可する方法もある。 |
| バスを分けずに個別ノードで音量調整 コードが煩雑に | 音の種 類ごとにAudio Busを分割 「BGM」「SFX」「Voice」でバス管理 |
| バスのインデックスをハードコーディング | バス名でインデックスを取得AudioServer.get_bus_index("BGM") |
効果音(SE)の正しい再生方法
# ベストプラクティス: ノードを動的生成して再生後削除
func play_sfx(sfx_stream: AudioStream):
var player = AudioStreamPlayer.new()
player.stream = sfx_stream
player.bus = "SFX"
add_child(player)
player.play()
player.finished.connect(func(): player.queue_free())
# 使い方
var attack_sfx = preload("res://assets/sfx/attack.ogg")
play_sfx(attack_sfx)
2D/3Dゲームの場合: 位置を持たせたい場合は
AudioStreamPlayer2DまたはAudioStreamPlayer3Dを使用し、global_positionを設定してください。
実践: シングルトンによるオーディオ管理
ゲーム全体のオーディオを統括するAudioManagerシングルトンを作成すると、どのシーンからでも簡単に音を制御できます。
プロジェクト設定:
- 「プロジェクト」→「プロジェクト設定」→「AutoLoad」タブ
AudioManager.gdを追加
# AudioManager.gd
extends Node
const BGM_BUS_NAME = "BGM"
const SFX_BUS_NAME = "SFX"
@onready var bgm_bus_index = AudioServer.get_bus_index(BGM_BUS_NAME)
@onready var sfx_bus_index = AudioServer.get_bus_index(SFX_BUS_NAME)
var bgm_player: AudioStreamPlayer
func _ready():
if bgm_bus_index == -1:
push_error("Audio Bus '%s' not found." % BGM_BUS_NAME)
if sfx_bus_index == -1:
push_error("Audio Bus '%s' not found." % SFX_BUS_NAME)
# BGMを再生(フェードイン付き)
func play_bgm(stream: AudioStream, fade_in_duration: float = 0.5):
if not bgm_player:
bgm_player = AudioStreamPlayer.new()
bgm_player.bus = BGM_BUS_NAME
add_child(bgm_player)
bgm_player.stream = stream
bgm_player.volume_db = -80.0
bgm_player.play()
var tween = create_tween()
tween.tween_property(bgm_player, "volume_db", 0.0, fade_in_duration)
# 効果音を再生
func play_sfx(stream: AudioStream, position: Vector2 = Vector2.ZERO):
var player: Node
if position == Vector2.ZERO:
player = AudioStreamPlayer.new()
else:
player = AudioStreamPlayer2D.new()
player.global_position = position
player.stream = stream
player.bus = SFX_BUS_NAME
add_child(player)
player.play()
player.finished.connect(func(): player.queue_free())
# BGMの音量を設定 (0.0 - 1.0)
func set_bgm_volume(linear_volume: float):
if bgm_bus_index == -1:
return
AudioServer.set_bus_volume_db(bgm_bus_index, linear_to_db(clampf(linear_volume, 0.0, 1.0)))
# SFXの音量を設定 (0.0 - 1.0)
func set_sfx_volume(linear_volume: float):
if sfx_bus_index == -1:
return
AudioServer.set_bus_volume_db(sfx_bus_index, linear_to_db(clampf(linear_volume, 0.0, 1.0)))
呼び出し例:
# player.gd
const JUMP_SOUND = preload("res://assets/sfx/jump.ogg")
func _process(delta):
if Input.is_action_just_pressed("jump"):
AudioManager.play_sfx(JUMP_SOUND, global_position)
パフォーマンスと代替パターン
大量のSEが同時に発生する場合の選択肢:
| アプローチ | メリット | デメリット | 適した状況 |
|---|---|---|---|
| 動的インスタンス化 | 実装がシンプル | 大量生成時にノード生成コスト | ほとんどのゲーム |
| オブジェクトプール | パフォーマンスが安定 | 実装が複雑 | 毎秒数十〜数百のSEが鳴るゲーム |
まずは動的インスタンス化から始め、プロファイリングでボトルネックが判明した場合にのみプールを検討するのが賢明です。
Audio Busへのエフェクト適用
バスにエフェクトを追加すると、そのバスを通る全ての音に一括で効果を適用できます。
- エディタ下部の「オーディオ」タブを開く
- エフェクトをかけたいバス(例:
SFX)を選択 - 「エフェクトの追加」から
AudioEffectReverbを選択 Room SizeやWetなどを調整
これ で洞窟や大聖堂のような残響を簡単に表現できます。
まとめ
| 概念 | 役割 | ベストプラクティス |
|---|---|---|
| AudioStreamPlayer | 音を鳴らすノード | SEは動的生成、BGMはシーンに固定配置 |
| Audio Bus | ミキシングコンソール | BGM/SE/Voiceでバスを分けて管理 |
| シングルトン | 一元管理 | AudioManagerで全体を統括 |
次のステップ:
- Audio Bus Layoutの永続化:
audio_bus_layout.tresとして保存 - BGMのループ設定:
.oggファイルのインポート設定で「Loop」を有効にする - AudioStreamPlayer2D/3Dの深掘り: 空間的な音の減衰やパンニング
- 高度なエフェクトチェーン: EQ → Compressor → Limiter