【Godot】Godotで実装するアダプティブミュージック【AudioStreamInteractive活用法】

作成: 2026-02-08

AudioStreamInteractiveとAudioStreamSynchronizedを使って、ゲーム状況に応じて動的に変化する音楽システムを実装する方法を解説します。

概要

動作確認環境: Godot 4.3+

ゲームの状況に応じて音楽が変化する「アダプティブミュージック」は、プレイヤーの没入感を高める重要な要素です。戦闘開始時に激しい曲に切り替わり、探索時には穏やかな曲に戻る――こうした動的な音楽制御を、GodotではAudioStreamInteractiveを使って簡単に実装できます。

本記事では、AudioStreamInteractive、AudioStreamPlaylist、AudioStreamSynchronizedの3つのクラスを使った実践的なアダプティブミュージックの実装方法を解説します。

AudioStreamInteractiveの基本

アダプティブミュージックの中核となるのがAudioStreamInteractiveです。まずは、このリソースの役割と基本的な仕組みを理解しましょう。

AudioStreamInteractive は、複数の音楽クリップを状態に応じて切り替えるためのリソースです。探索中は穏やかな曲、戦闘中は激しい曲、のように場面に応じてBGMを動的に変更できます。

主要な機能

  • クリップ管理: 複数の音楽状態(探索、戦闘、ボス戦など)を1つのリソースで管理
  • トランジション制御: クリップ間の遷移タイミング・方法を細かく設定
  • 自動ループ: 各クリップのループ設定を個別に管理

「AudioStreamPlaylistとどちらを使えばいいの?」と迷う方も多いかもしれません。以下の比較表で違いを確認しましょう。

AudioStreamPlaylistとの違い

機能AudioStreamInteractiveAudioStreamPlaylist
用途状態遷移型BGMシーケンシャル/ランダム再生
トランジション詳細設定可能単純な次曲移行のみ
クリップ切り替えswitch_to_clip_by_name() で任意切り替え自動再生順序

探索/戦闘のような状態遷移には AudioStreamInteractive、環境音楽のランダム再生には AudioStreamPlaylist が適しています。

トランジション設定

AudioStreamInteractiveの基本がわかったところで、次はその最大の魅力であるトランジション設定に進みましょう。曲の切り替わり方ひとつで、プレイヤーの体感は大きく変わります。

AudioStreamInteractive の強みは、クリップ間の遷移を細かく制御できる 点にあります。即座に切り替えるか、曲の終わりで切り替えるか、拍に合わせるかを個別に設定できます。

エディタでのセットアップ

AudioStreamInteractive は エディタのインスペクタで設定するのが基本 です。GDScript からの動的構築はAPIが限定的なため、.tres リソースとして作成しましょう。

  1. FileSystemで右クリック →「新規リソース」→ AudioStreamInteractiveを選択
  2. インスペクタで Clip Count を設定(例: 2)
  3. 各クリップに名前と AudioStream を割り当て
  4. Transitions セクションで遷移設定を追加
  5. .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)

トランジション設定(エディタ)

上記のスクリプトと組み合わせて使うエディタ側の設定手順です。

  1. AudioStreamInteractive リソースを作成
  2. Clips タブで探索BGMと戦闘BGMを追加
  3. 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 では再生制御に集中する

さらに学ぶために