概要
動作確認環境: Godot 4.3+
ゲームの状況に応じて 音楽が変化する「アダプティブミュージック」は、プレイヤーの没入感を高める重要な要素です。戦闘開始時に激しい曲に切り替わり、探索時には穏やかな曲に戻る――こうした動的な音楽制御を、GodotではAudioStreamInteractiveを使って簡単に実装できます。
本記事では、AudioStreamInteractive、AudioStreamPlaylist、AudioStreamSynchronizedの3つのクラスを使った実践的なアダプティブミュージックの実装方法を解説します。
AudioStreamInteractiveの基本
アダプティブミュージックの中核となるのがAudioStreamInteractiveです。まずは、このリソースの役割と基本的な仕組みを理解しましょう。
AudioStreamInteractive は、複数の音楽クリップを状態に応じて切り替えるためのリソースです。探索中は穏やかな曲、戦闘中は激しい曲、のように場面に応じてBGMを動的に変更できます。
主要な機能
- クリップ管理: 複数の音楽状態(探索、戦闘、ボス戦など)を1つのリソースで管理
- トランジション制御: クリップ間の遷移タイミング・方法を細かく設定
- 自動ループ: 各クリップのループ設定を個別に管理
「AudioStreamPlaylistとどちらを使えばいいの?」と迷う方も多いかもしれません。以下の比較表で違いを確認しましょう。
AudioStreamPlaylistとの違い
| 機能 | AudioStreamInteractive | AudioStreamPlaylist |
|---|---|---|
| 用途 | 状態遷移型BGM | シーケンシャル/ランダム再生 |
| トランジション | 詳細設定可能 | 単純な次曲移行のみ |
| クリップ切り替え | switch_to_clip_by_name() で任意切り替え | 自動再生順序 |
探索/戦闘のような状態遷移には AudioStreamInteractive、環境音楽のランダム再生には AudioStreamPlaylist が適しています。
トランジション設定
AudioStreamInteractiveの基本がわかったところで、次はその最大の魅力であるトランジション設定に進みましょう。曲の切り替わり方ひとつで、プレイヤーの体感は大きく変わります。
AudioStreamInteractive の強みは、クリップ間の遷移を細かく制御できる 点にあります。即座に切り替えるか、曲の終わりで切り替えるか、拍に合わせるかを個別に設定できます。
エディタでのセットアップ
AudioStreamInteractive は エディタのインスペクタで設定するのが基本 です。GDScript からの動的構築はAPIが限定的なため、.tres リソースとして作成しましょう。
- FileSystemで右クリック →「新規リソース」→
AudioStreamInteractiveを選択 - インスペクタで Clip Count を設定(例: 2)
- 各クリップに名前と AudioStream を割り当て
- Transitions セクションで遷移設定を追加
.tresファイルとして保存
エディタでリソースを作成したら、スクリプトからはpreloadで読み込んで再生するだけです。
# エディタで作成した .tres リソースを読み込んで再生
var music = preload("res://audio/bgm_interactive.tres")
$AudioStreamPlayer.stream = music
$AudioStreamPlayer.play()
遷移タイミングの種類
遷移のタイミングは3種類から選べます。
# 即座に遷移
AudioStreamInteractive.TRANSITION_FROM_TIME_IMMEDIATE
# 現在の曲の終わりで遷移
AudioStreamInteractive.TRANSITION_FROM_TIME_END
# 次の拍で遷移
AudioStreamInteractive.TRANSITION_FROM_TIME_NEXT_BEAT
戦闘開始時には即座に切り替え、戦闘終了時には曲の終わりで遷移させるなど、状況に応じて使い分けます。
レイヤー型音楽システム
クリップの切り替え以外にも、音楽の変化を表現する方法があります。同じ曲のレイヤー(パート)を増減させるアプローチです。たとえばアクションゲームで敵の数が増えるとドラムが加わり、ボスが出現するとメロディが重 なる――そんな段階的な演出に向いています。
AudioStreamSynchronized を使うと、複数の音楽トラックを同期再生し、各トラックのボリュームを個別に制御できます。
基本構成
以下のコードでは、ドラム・ベース・メロディの3トラック構成を作成しています。メロディだけミュート状態でスタートし、必要なタイミングでフェードインさせます。
# レイヤー型音楽の作成
var layered_music = AudioStreamSynchronized.new()
# トラックを追加
layered_music.stream_count = 3
layered_music.set_sync_stream(0, drums_track) # ドラム
layered_music.set_sync_stream(1, bass_track) # ベース
layered_music.set_sync_stream(2, melody_track) # メロディ
# 初期ボリューム設定
layered_music.set_sync_stream_volume(0, 0.0) # ドラム(通常)
layered_music.set_sync_stream_volume(1, 0.0) # ベース(通常)
layered_music.set_sync_stream_volume(2, -80.0) # メロディ(ミュート)
$AudioStreamPlayer.stream = layered_music
$AudioStreamPlayer.play()
動的なレイヤー制御
ゲームプレイ中にレイヤーを増減させるには、ボリューム値を変更します。set_sync_stream_volume() で即座に切り替えることもできますが、Tween を使うと滑らかなフェードイン/アウトになり、プレイヤーに違和感を与えません。
# 戦闘開始時:メロディレイヤーをフェードイン
func start_combat():
var music = $AudioStreamPlayer.stream as AudioStreamSynchronized
var tween = create_tween()
tween.tween_method(
func(db): music.set_sync_stream_volume(2, db),
-80.0, 0.0, 1.0 # 1秒かけてフェードイン
)
# 戦闘終了時:メロディレイヤーをフェードアウト
func end_combat():
var music = $AudioStreamPlayer.stream as AudioStreamSynchronized
var tween = create_tween()
tween.tween_method(
func(db): music.set_sync_stream_volume(2, db),
0.0, -80.0, 1.0 # 1秒かけてフェードアウト
)
実装例:探索/戦闘BGM切り替え
ここまでの知識を組み合わせて、実際にゲームで使えるBGMマネージャーを作ってみましょう。探索と戦闘の2状態を切り替えるシンプルな構成です。
extends Node
@onready var music_player = $AudioStreamPlayer
var current_state = "exploration"
func _ready():
# AudioStreamInteractive リソースを設定
var music = preload("res://audio/bgm_interactive.tres")
music_player.stream = music
music_player.play()
# 戦闘開始
func enter_combat():
if current_state != "combat":
switch_to("combat")
current_state = "combat"
# 探索に戻る
func exit_combat():
if current_state != "exploration":
switch_to("exploration")
current_state = "exploration"
# クリップ切り替え
func switch_to(clip_name: String):
var playback = music_player.get_stream_playback() as AudioStreamPlaybackInteractive
playback.switch_to_clip_by_name(clip_name)
トランジション設定(エディタ)
上記のスクリプトと組み合わせて使うエディタ側の設定手順です。
AudioStreamInteractiveリソースを作成- Clips タブで探索BGMと戦闘BGMを追加
- Transitions タブで遷移設定:
- 探索→戦闘:
TRANSITION_FROM_TIME_IMMEDIATE(即座に切り替え) - 戦闘→探索:
TRANSITION_FROM_TIME_END(曲の終わりで切り替え)
- 探索→戦闘:
ベストプラクティス
アダプティブミュージックの実装で陥りがちな落とし穴と、それを避けるためのポイントをまとめました。
- 1つのAudioStreamPlayerで管理: BGM用の AudioStreamPlayer は1つのみ使用し、
switch_to_clip_by_name()でクリップを切り替える - トランジションタイミングの最適化: 戦闘開始は即座に、戦闘終了は曲の終わりで遷移させると自然
- レイヤー型とクリップ型の併用: 複雑な音楽システムには、AudioStreamInteractive の各クリップに AudioStreamSynchronized を設定
- フェード時間の調整: 急激な音量変化を避けるため、トランジションにフェードを設定(0.5〜1.0秒程度)
- 状態管理の明確化:
current_state変数で現在のBGM状態を管理し、不要なtravel()呼び出しを防ぐ
まとめ
- AudioStreamInteractive は複数のBGMクリップを状態に応じて切り替えるシステム
- トランジション設定 で遷移タイミング・方法を細かく制御可能
- AudioStreamSynchronized を使うとレイヤー型の音楽シス テムが実装できる
switch_to_clip_by_name()でクリップを切り替え、set_sync_stream_volume()でボリューム制御- 1つの AudioStreamPlayer で複数のBGM状態を管理するのがベストプラクティス
- AudioStreamInteractive の設定は エディタのインスペクタ で行い、GDScript では再生制御に集中する