この記事では、「AudioStreamPlayer」ノード 1 つで複数のサウンドリソース(音楽や効果音のファイル)を切り替えて再生する方法を説明する。

基本的に、「AudioStreamPlayer」系のクラスは、ノード1つに対して、設定できるサウンドリソースは1つだけだ。つまり、サウンドリソースの数だけシーンツリー内に「AudioStreamPlayer」ノードを追加しなければならない。サウンドリソース以外全て同じ設定のノードがシーンツリー内に複数存在する(以下のスクリーンショットのような)状況には無駄を感じるだろうし、またシーンドックの視認性が悪くて少し嫌になるかもしれない。
project settings - window size

そこで、同時に鳴らすことがない複数のサウンドリソースがある場合(例えば、キャラクターの攻撃の種類に応じた複数の効果音やUI上のボタンの種類に応じた複数の効果音など)、プロジェクトには用途ごとに必要最小限の「AudioStreamPlayer」ノードだけ追加しておき、それぞれスクリプトから状況に応じてサウンドリソースを切り替えれば無駄がなく、シーンドックの見た目もスッキリするはずだ。

ということで、ここからのチュートリアルでは、「AudioStreamPlayer」ノードは1つだけ用意して、そこに適用するサウンドリソースをスクリプトから切り替えて、再生できるように制御していく。

Environment
Godot のバージョン: 3.5.1
コンピュータのOS: macOS 12.6

Basic Articles
以下の記事もお役立てください。
Godot をダウンロードする
Godot のプロジェクトマネージャー
Godot の言語設定



準備

プロジェクト設定

新規プロジェクトを立ち上げたら、「プロジェクト」メニュー>「プロジェクト設定」から以下の設定を行なう。

  • 「一般」タブ > サイドバー「Display」>「Window」>「Size」セクションにて、ウインドウサイズを以下のように設定する。
    project settings - window size

サウンドリソースのダウンロード

以下のDropboxの共有フォルダに 6 つの .wav ファイル(効果音)を用意している。

Dropbox - 共有フォルダ

ダウンロードした「audio」フォルダごとファイルシステムドックへドラッグ&ドロップしてプロジェクトへ追加する。
sound resources - add to the file system


シーンの作成

以下のようなシーンツリーを作る。今回は過去最高にシンプルなツリーである。

  • UI (Control)
    • SoundLabel (Label)
    • AudioStreamPlayer

Scene tree

シーンツリーの作成が完了したら、ファイル名を「UI.tscn」として保存しておく。



ノードの編集

UI (Control) ルートノード

このルートノードの「Anchor」を画面サイズと同じになるよう拡げておく。理由は、このあと子ノードの「SoundLabel」を画面の中央に配置したいからだ。

  • 2D ワークスペースのツールバーから「Layout」>「全画面(Full Rect)」を選択する。これで「Anchor」プロパティは自動的に調整され、2D ワークスペース上も以下のようになる。
    UI node - Layout - Full Rect

SoundLabel (Label) ノード

このノードは、現在「AudioStreamPlayer」ノードの「Stream」プロパティに適用されているサウンドリソースのパスを表示するために利用する。これにより、プロジェクトを実行して動作確認をする時に、今どのリソースファイルを適用および再生しているのかがひと目でわかる。

  • インスペクターにて「Text」プロパティには一旦「no sound」と仮に入れておく。
    SoundLabel node - Text
  • 「Align」プロパティを「Center」に変更する。これで「Text」の文字列が水平方向で中央に表示される。
    SoundLabel node - Align
  • 「Control」クラスの「Grow Direction」>「Horizontal」プロパティを「Both」に変更する。これで「Text」の文字数が増えても左右両方向に拡大するので、常に画面中央に表示される。
    SoundLabel node - Grow Direction - Horizontal
  • 2D ワークスペースのツールバーから「Layout」>「中央」を選択する。2D ワークスペース上も以下のようになる。
    SoundLabel node - Layout - Center

AudioStreamPlayer ノード

このノードはサウンドリソースを適用して、それを再生するためのノードだ。ノードの作りとして、もともと1つのサウンドリソースしか設定できない仕様であるが、今回のチュートリアルでは、このノード1つで、複数のサウンドリソースを切り替えて再生させる。その制御はのちほどスクリプトにて行うことになるが、ここではひとまずノードの設定をしておく。

  • ファイルシステムドックから先にインポートしておいたサウンドリソースファイルのうち「res://auido/coin.wav」を、インスペクターの「Stream」プロパティへドラッグ&ドロップして適用する。ひとまずこれをデフォルトのサウンドリソースとする。


UI ルートノードにスクリプトをアタッチする

いよいよ、サウンドリソースを設定と再生を制御するためのスクリプトを作成していく。まずはルートノード「UI」に新規でスクリプトをアタッチする。このときスクリプトのファイル名は「UI.gd」としておく。スクリプトをアタッチして、スクリプトエディタが開いたら、以下のようにコードを編集する。

extends Control

# 定数としてプリロードしたサウンドリソースを配列にしておく
const sounds = [
    # デフォルトのリソースを1番目の要素にしている
	preload("res://auido/coin.wav"),
	preload("res://auido/heal.wav"),
	preload("res://auido/hurt.wav"),
	preload("res://auido/shoot1.wav"),
	preload("res://auido/shoot2.wav"),
	preload("res://auido/shoot3.wav"),
]

# 配列 sounds の要素のうち AudioStreamPlayer に設定する
# リソースを指定するためのインデックス(0 から 5 まで)
var index: int = 0

# SoundLabel の参照
onready var sound_label = $SoundLabel
# AudioStreamPlayer の参照
onready var player = $AudioStreamPlayer


# ノードが読み込まれたら実行される組込み関数
func _ready():
    # サウンドを再生するメソッドを呼び出す(あとで定義)
	play_sound()


# 組み込みプロセス関数(毎フレーム呼び出される)
func _process(_delta):
    # 右矢印キーが押されたら
	if Input.is_action_just_pressed("ui_right"):
        # 現在のインデックスが配列 sounds の最後のインデックス(5)
        # より小さければ現在のインデックスに 1 を足す
		if index < sounds.size() - 1:
			index += 1
        # 現在のインデックスが配列 sounds の最後のインデックス(5)
        # であればインデックスを 0 に戻す
		else:
			index = 0
        # サウンドを再生するメソッドを呼び出す(あとで定義)
		play_sound()
    
    # 左矢印キーが押されたら
	if Input.is_action_just_pressed("ui_left"):
        # 現在のインデックスが 0 より大きければ
        # 現在のインデックスから 1 を引く
		if index > 0:
			index -= 1
        # 現在のインデックスが 0 であれば
        # インデックスを配列 sounds の最後のインデックスと同じ(5)にする
		else:
			index = sounds.size() - 1
        # サウンドを再生するメソッドを呼び出す(あとで定義)
		play_sound()
    
    # スペースバーかエンターキーが押されたら
	if Input.is_action_just_pressed("ui_accept"):
        # サウンドを再生するメソッドを呼び出す(あとで定義)
		play_sound()


# サウンドを再生するメソッド
func play_sound():
    # 配列 sounds から現在のインデックスに該当する要素を取得して
    # AudioStreamPlayer の Stream プロパティに適用する
	player.stream = sounds[index]
    # AudioStreamPlayer の Stream プロパティのリソースパスを
    # SoundLabel の Text プロパティに 設定する
	sound_label.text = player.stream.resource_path
    # AudioStreamPlayer の Stream プロパティのサウンドリソースを再生
	player.play()

これでスクリプトの編集は完了だ。

なお、今回はpreloadを利用して、ノードが読み込まれるタイミングでサウンドリソースも読み込んでおくようにした。これは、処理の多いゲームの場合、動作遅延回避策になるだろう。反対に、大して処理が多くないのであればloadを利用して、再生する直前にリソースファイルを読み込んでも問題ないだろう。詳しくは以下の記事が大変参考になるので併せてご覧いただきたい。

2dgames.jp -【Godot】サウンドを動的にロードして再生する方法



動作確認

最後にプロジェクトまたはシーンを実行して動作確認しておく。

ここまでで実装した通り、以下のキーボード操作でサウンドリソースを切り替え、再生できる。

  • 右矢印キー: 「UI.gd」スクリプトの配列sounds上の次のサウンドリソースに切り替えて再生
  • 左矢印キー: 「UI.gd」スクリプトの配列sounds上の前のサウンドリソースに切り替えて再生
  • スペースバー / エンターキー: 現在設定されているサウンドリソースを再生


おわりに

今回のチュートリアルは、1つの「AudioStreamPlayer」ノードで複数のサウンドリソースを切り替えて再生する方法についてお伝えした。大事なポイントをまとめておこう。

  • 「AudioStreamPlayer」1つで複数のサウンドリソースを切り替えて再生できる。
  • 上記手法は、設定がほとんど同じ複数の「AudioStreamPlayer」ノードを追加する無駄を回避し、シーンツリーの視認性を向上する目的で実装する。
  • サウンドの切り替えと再生はスクリプトで制御する。

もちろん、プログラミングが苦手な場合は、サウンドリソースの数だけ「AudioStreamPlayer」ノードをシーンに追加しても全く問題ない。今回紹介したのは、あくまで一つの方法論に過ぎないので、特にインディー開発の場合は自由にやっていただきたい。



参考