探索中はゆったりしたBGM、敵と戦い始めた瞬間に激しい曲へ切り替わり、ボスが出るとさらに盛り上がる——名作ゲームのあの 「音楽が状況に反応する」 演出。同じBGMを延々ループさせるだけだと、どうしても場面の緊張感が出せません。
この動的な音楽制御を アダプテ ィブミュージック と呼び、Godot 4.3以降では AudioStreamInteractive と AudioStreamSynchronized で実装できます。この記事では、2つのアプローチの違いから、切り替えタイミングの設計、探索⇄戦闘を切り替えるBGMマネージャーの実装までを組み立てます。
この記事でわかること
- アダプティブミュージックの 2つのアプローチ(クリップ切替型 / レイヤー重ね型)
AudioStreamInteractiveで 状態に応じてBGMクリップを切り替える- 切り替えの タイミング(即座・曲末・次の拍)の使い分け
AudioStreamSynchronizedで パートを足し引き するレイヤー型- 探索⇄戦闘のBGMマネージャー を1プレイヤーで組む
2つのアプローチ:クリップ切替とレイヤー重ね
アダプティブミュージックには、大きく2つの作り方があります。どちらを選ぶかで使うクラスが変わります。

- クリップ切替型 :探索用・戦闘用など、 曲そのものを丸ごと入れ替える 。場面ごとに全く違う曲を用意でき、変化がはっきりします。→
AudioStreamInteractive - レイヤー重ね型 :同じ曲の パート(ドラム・ベース・メロディ)を足し引き する。敵が増えたらドラムを足す、といった段階的で滑らかな盛り上げが得意です。→
AudioStreamSynchronized
どちらか一方だけでなく、 併用 もできます(切り替えた各クリップの中身をレイヤー型にする)。まずはそれぞれを見ていきましょう。
AudioStreamInteractive:曲を切り替える
AudioStreamInteractive は、 複数の音楽クリップを状態に応じて切り替える リソースです。探索・戦闘・ボスといった状態を1つのリソースにまとめ、ゲームの状況が変わるたびに対応するクリップへ遷移します。

AudioStreamInteractive は、GDScriptからの構築APIが限定的なため、 エディタのインスペクタで作るのが基本 です。
- FileSystemで右クリック →「新規リソース」→
AudioStreamInteractive - Clip Count を設定し、各クリップに名前とAudioStreamを割り当て(例:
exploration・combat) - Transitions で遷移のタイミングを設定
.tresとして保存
スクリプト側は、作ったリソースを読み込んで再生するだけです。
# エディタで作った .tres を読み込んで再生
var music := preload("res://audio/bgm_interactive.tres")
$AudioStreamPlayer.stream = music
$AudioStreamPlayer.play()
切り替えのタイミング
AudioStreamInteractive の強みは、 クリップの切り替わり方を細かく選べる ことです。同じ「戦闘へ切り替え」でも、タイミング1つで体感が大きく変わります。

| タイミング | 定数 | 使いどころ |
|---|---|---|
| すぐ切り替え | TRANSITION_FROM_TIME_IMMEDIATE | 戦闘開始など、即座に緊張感を出したいとき |
| 曲の終わりで | TRANSITION_FROM_TIME_END | 戦闘終了→探索など、自然に戻したいとき |
| 次の拍で | TRANSITION_FROM_TIME_NEXT_BEAT | リズムを崩さず滑らかに切り替えたいとき |
戦闘開始は IMMEDIATE でパッと切り替え、戦闘終了は END で曲を締めてから戻す——このように 入りは即座・戻りは自然 に使い分けると、音楽が場面にきれいに寄り添います。
AudioStreamSynchronized:レイヤーを重ねる
もう1つのアプローチが、 同じ曲のパートを増減させる レイヤー型です。AudioStreamSynchronized は複数トラックを ぴったり同期して同時再生 し、各トラックの音量を個別に制御できます。

まずドラム・ベース・メロディの3トラックを用意し、メロディだけミュートで始めます。
var layered := AudioStreamSynchronized.new()
layered.stream_count = 3
layered.set_sync_stream(0, drums_track) # ドラム
layered.set_sync_stream(1, bass_track) # ベース
layered.set_sync_stream(2, melody_track) # メロディ
layered.set_sync_stream_volume(0, 0.0) # ドラム:通常
layered.set_sync_stream_volume(1, 0.0) # ベース:通常
layered.set_sync_stream_volume(2, -80.0) # メロディ:ほぼ無音(後で上げる)
$AudioStreamPlayer.stream = layered
$AudioStreamPlayer.play()
戦闘に入ったら、メロディの音量を Tween でじわっと上げます。いきなり足すと唐突なので、フェードで重ねるのがコツです。
# 戦闘開始:メロディレイヤーをフェードイン
func start_combat() -> void:
var music := $AudioStreamPlayer.stream as AudioStreamSynchronized
# -80dB(無音)→0dB(通常)へ1秒でフェード
create_tween().tween_method(
func(db): music.set_sync_stream_volume(2, db), -80.0, 0.0, 1.0)
全パートが同じタイミングで鳴っているので、音量を上げ下げするだけで ズレずに レイヤーを足し引きできます。これがレイヤー型の気持ちよさです。
実践:探索⇄戦闘のBGMマネージャー
クリップ切替型を使って、実際のゲームで使えるBGMマネージャーを組んでみましょう。アクションRPGの探索⇄戦闘、ローグライクのフロア⇄ボス、ステルスの通常⇄発見——「2つの状態を行き来する」構造はジャンルを問わず同じ形で作れます。

ポイントは、 BGM用の AudioStreamPlayer は1つだけ に保ち、再生中のplaybackからクリップを切り替えることです。Autoload にして、どのシーンからでも呼べるようにしておくと便利です。
extends Node
@onready var music_player: AudioStreamPlayer = $AudioStreamPlayer
var current_state := "exploration"
func _ready() -> void:
music_player.stream = preload("res://audio/bgm_interactive.tres")
music_player.play()
func enter_combat() -> void:
if current_state != "combat": # 同じ状態への無駄な切り替えを防ぐ
switch_to("combat")
current_state = "combat"
func exit_combat() -> void:
if current_state != "exploration":
switch_to("exploration")
current_state = "exploration"
func switch_to(clip_name: String) -> void:
# 再生中のplaybackを取得し、名前でクリップを切り替える
var playback := music_player.get_stream_playback() as AudioStreamPlaybackInteractive
playback.switch_to_clip_by_name(clip_name)
ポイントは2つです。
- プレイヤーは1つ、状態で中身を切り替える :BGMごとに
AudioStreamPlayerを増やすと、二重再生や消し忘れの温床になります。1プレイヤー+switch_to_clip_by_name()に集約するのが鉄則です。 - 現在の状態を覚えておく :
current_stateで今のBGMを記録し、 同じ状態への切り替えをスキップ します。これを怠ると、戦闘中に敵と遭遇するたびBGMが頭から鳴り直してしまいます。
エディタ側では、探索→戦闘を IMMEDIATE、戦闘→探索を END に設定しておくと、入りは鋭く・戻りは自然になります。
ベストプラクティス
- BGMは1プレイヤーに集約 :
AudioStreamPlayerを1つに保ち、switch_to_clip_by_name()でクリップを替える - 入りは即座・戻りは自然 :戦闘開始は
IMMEDIATE、終了はENDでトランジションを設計する - フェードで滑らかに :レイヤーの増減やクリップ音量は、0.5〜1.0秒のフェードで急変を避ける
- 状態を明確に管理 :
current_stateで現在のBGMを持ち、 同じ状態への無駄な切り替え を防ぐ - クリップ型とレイヤー型は併用可 :各クリップの中身を
AudioStreamSynchronizedにすれば、状態切替と段階的盛り上げを両立できる
おまけ:先に知っておくと良いこと
- 単純な連続再生なら
AudioStreamPlaylist:BGMを順番/ランダムに流すだけなら、遷移設定のないこちらがシンプルです。状態遷移が要るならAudioStreamInteractiveを選びます。 - エディタで作り、コードは再生制御に集中 :
AudioStreamInteractiveはインスペクタでの構築が前提です。GDScriptは「いつ・どのクリップへ」の指示だけに絞ると見通しが良くなります。 - 切り替えのきっかけは シグナル で :敵の発見やボスの出現を各所から
AudioManagerに伝えるには、状態変化をシグナルで飛ばすと疎結合に保てます。 - バス構成やエフェクトは基礎編へ :BGMバスの音量やフェードは オーディオ管理の基礎 と AudioBusエフェクト が土台になります。
まとめ
- 2アプローチ :
AudioStreamInteractive(曲まるごと切替)とAudioStreamSynchronized(パートを足し引き) - トランジション :
IMMEDIATE(即座)・END(曲末)・NEXT_BEAT(拍)を場面で使い分ける - レイヤー型 は各トラックの音量を Tween でフェードして重ねる
- 実践 :1つの
AudioStreamPlayer+switch_to_clip_by_name()で状態ごとにクリップを切 替、current_stateで無駄な切り替えを防ぐ
まずは探索用と戦闘用の2曲で AudioStreamInteractive を作り、IMMEDIATE と END の違いを耳で確かめてみてください。音楽が場面に反応し始めると、ゲームの手応えが一段深くなります。
さらに学ぶために
- オーディオ管理の基礎(AudioStreamPlayerとAudio Bus) ——BGM再生とバスの土台
- AudioBusエフェクトでサウンドデザイン ——BGMバスの音作り・フェード
- Tweenで実現する滑らかなアニメーション ——レイヤー音量やフェードを滑らかに
- Autoloadによるシーンをまたぐデータ管理 ——BGMマネージャーをシングルトンにする
- Godot公式ドキュメント:AudioStreamInteractive ——クリップとトランジションの一次情報