はじめに
ADXアンバサダーとして記事を書いておりますSigと申します。
この記事では、アンリアルエンジン5とサウンドミドルウェア「ADX for UE」を連携させ、UE5のGameplayTagSystem機能を使ってサウンドを再生処理を管理する実装を紹介します。
ゲームが大きくなるにつれて、サウンド関連のBPが肥大化し「どこで何を鳴らしているか」を追いづらくなる問題が出てきます。キャラクターや操作、行動、シチュエーションなどのバリエーションにより再生処理が増えていくと、処理の差し替えや変更に弱い構造ができてしまいます。
例として、このような状況が考えられます。
- 攻撃音・被弾音・死亡音…とキュー数が増え、どのBPから呼ばれているか追いにくい
- キャラクターごとに似たようなサウンド再生BPを何度も書いている
- 後からサウンドを差し替えたいのに、影響範囲が広くて手が出せない
特に重複したサウンド再生処理がゲーム全体に散らばってしまうのが問題になります。後から処理やサウンドを変更するたびに、影響する箇所やリファレンスをチェックする必要が出てきます。
これらを、タグによりサウンドを識別・管理する設計により解決を試みてみましょう。
前提
「ADX for UE LE」を使用します。導入や簡単な使い方は以下の記事にあります。
ADX for UEの導入で、一歩上のサウンド表現を(導入編)
ADX for UEの導入で、一歩上のサウンド表現を(実践編)
実装
設計
本記事の処理では、以下の流れでサウンドを再生します。
- GameplayTagを用意
- データテーブルに「タグ→キュー」の対応を定義しておく
- ゲーム側のブループリントでは直接キューを指定せず、タグによってサウンドを再生する関数を呼ぶ
- 関数内部でデータテーブルを参照し、タグに対応するキューを再生する
これにより、BPの配線を増やさずに大量のサウンドを整理でき、後からの差し替えも容易になります。
AtomCraftでサウンドを用意する
キューの作成
今回は例として、戦闘関連のサウンドを用意しました。
- 「SE_Attack_Light」: 軽い攻撃音
- 「SE_Attack_Heavy」: 重い攻撃音
- 「SE_Hit_Normal」: 通常の被弾音
- 「SE_Hit_Critical」: クリティカル被弾音
マテリアルツリーにインポートします。
マテリアルをすべて選択してキューシートにドラッグ&ドロップします。
それぞれのマテリアルに対したキューが作られます。
キューシートのビルド
シンプルに再生するだけならこれだけでOKです。キューシートをビルドします。
UE5でタグに紐づいた再生処理を作る
キューシートのインポート
UE5のコンテンツドロワーにビルドしたacbファイル、acfファイルをドラッグ&ドロップしてインポートします。
acfファイルインポート時のダイアログでは両方とも「Yes」を選択します。これにより、プロジェクトにAtom Configが自動的に設定されます。
acbファイル、acfファイルに対してアセットが作られます。
キューシートを開き、キューが正常に再生されることを確認します。
GameplayTagを定義する
プロジェクト設定でGameplayTagを定義します。
「GameplayTags」の「Manage Gameplay Tags」から、Gameplay Tagの管理画面を開きます。

まずは「Sound」という大きなカテゴリとなるタグを追加します。

Soundタグを右クリックし、「Add Sub Tag」からサブタグを追加します。

「Sound.Combat.Attack.Light」のように、「.」で区切って階層化されたタグを作ります。

このように、自動的に階層に振り分けられます。

同じように以下のタグを追加します。
「Sound.Combat.Attack.Heavy」
「Sound.Combat.Hit.Normal」
「Sound.Combat.Hit.Critical」
タグとキューを紐づけるDataTableを作る
まずDataTableの規格に使用する構造体を作成します。
コンテンツドロワーで右クリックし、「Blueprints」→「Structure」で新規構造体を作成します。
ダブルクリックして開き、ふたつの変数を追加します。「Atom Sound Cue」型のSoundCue、「String」型のDescriptionです。
前者はキューの指定、後者はサウンドを識別するためのメモ用として使用します。

この構造体を元にデータテーブルを作成します。
コンテンツドロワーを右クリックし、「Miscellaneous」(その他)→「Data Table」を選択。

使用する構造体には先ほど作ったものを指定します。

「DT_SoundTagMap」と名前をつけます。

「Row Name」(行の名前)では該当するタグを入力します。

タグに対応するキューを指定し、Descriptionに分かりやすいメモをつけておきます。

タグからサウンドを再生する共通関数を作る
サウンド再生用のキューは汎用のものとし、どこからでも呼び出せるようにしたいところです。
そこで、関数はBlueprint Function Libraryに作成します。
コンテンツドロワーで右クリックし、「Blueprints」→「Blueprint Function Library」を選択。

ダブルクリックして開き、関数「PlaySoundByTag」を作成します。

GameplayTag型の変数「SoundTag」を追加します。

Data Table型の変数「SoundDataTable」を追加します。

デフォルト値として、作成したデータテーブルを指定します。
別のデータテーブルを作った場合、ここを差し替えることでゲーム内のサウンドセットを一括で切り替えることが可能です。

Get Data Table Rowノードでデータテーブルを取得します。

Row Nameには引数で取得したSound Tagから、Get Tag Nameでタグ名を取得し繋げます。

取得した行の情報を、Break FSound Tag Rowで分解します。

Play Sound 2Dノードでサウンドを再生します。
ここでは必ずAtomカテゴリにあるものを選択します。Audioカテゴリの同名ノードは、UE5デフォルトのサウンド再生用のためAtomキューに対応していません。

ゲーム側からタグを指定してサウンドを再生する
ゲーム側からは作成した関数Play Sound by Tagを使用して再生します。
ここでは、登録したGameplay Tagを指定するだけです。


これで処理は完成です。
サウンド数が増えてきたプロジェクトや、複数のキャラクターやシチュエーションで似たようなサウンド再生が発生するプロジェクトに有効な設計です。
拡張性のある構造を保つための実装アプローチとして活用してみてください。
この機能を活用し、ゲームシーンに使う実装についてはこちらの記事で紹介しています。
補足
ボリュームやピッチを指定できるようにする
Play Sound 2Dノードの「Volume Multiplier」「PitchMultiplier」のインプットピンから関数の開始ノードまでドラッグ&ドロップすることで、引数が追加されます。


座標を指定し、立体的なサウンドを再生する
これまでの関数をリネームし、「PlaySoundByTag2D」とします。

関数を右クリックし、「Duplicate」で複製します。

「PlaySoundByTagAtLocation」と名前をつけました。

こちらでは、Play Sound 2DノードをPlay Sound at Locationノードに差し替えます。
また、「Location」のインプットピンをドラッグ&ドロップして引数にしておきます。

指定タグが参照できなかった場合にエラーメッセージを表示する
入力したタグに対応するキューがなかった場合や設定漏れの場合に、エラーメッセージを表示して分かりやすくすると安心です。























