はじめに
ADXアンバサダーとして記事を書いておりますSigと申します。
この記事ではUE5とADX for UEを連携させ、マルチプレイヤーゲームにおけるサウンドの実装を行っていきます。
前回の「基本編」に続き、
- 全員が同じサウンドを聞く
- 人によって異なるサウンドを聞く
ことに重点を置いた処理を作っていきます。
基本編はこちらから参照してください:
やること
- ADX for UEを使って、マルチプレイヤー対応のサウンドを再生する
- すべてのプレイヤーが同じタイミングでBGMを再生・停止できる「BGMManager」をつくる
- ゲームの状況から、特定のプレイヤーにのみ聞こえるサウンドを再生する(自分のみ、同チームのみなど)
- 補足: サーバーとクライアントの扱いの違い
また、記事中に「blueprintue」を使用したBPグラフ共有を載せています。コピペするだけで大体の実装ができますので、よろしければご活用ください。
当記事ではUE5.6 及び 「ADX LE UE SDK(2.04.02)」を使用します。
また、基本的にブループリントのみでの実装を行います。
ADX for UEはインディー向けの「LE版」であれば、無料で使用できます。
https://game.criware.jp/products/adx-le/
前提
「ADX for UE LE」を使用します。導入や簡単な使い方は以下の記事にあります。
ADX for UEの導入で、一歩上のサウンド表現を(導入編)
ADX for UEの導入で、一歩上のサウンド表現を(実践編)
実装
UE5でマルチプレイ対応のサウンドを実装する
すべてのプレイヤーに同じサウンド体験をさせる
全プレイヤーが同じ音を聞くことができる仕組みを作ります。
たとえばBGMなど、参加している人すべてに同じ体験をさせたい場合に使用します。
BGM管理アクターを作る
全員に向けてBGMを再生する処理をまとめるため、専用のアクターを作ります。
コンテンツドロワーの空欄で右クリックし、「Blueprint Class」を選択します。

親クラスは「Actor」を選びます。

作成したアクターに名前をつけます。

ダブルクリックして開き、イベントグラフにふたつのカスタムイベントノードを作ります。
カスタムイベント名の頭には「Server_」「Multicast_」とつけておきます。
これによって、それぞれ「Executes On Server」「Executes On All」と表示されていることを確認します。
カスタムイベントの接頭詞により、ネットワークイベントの挙動が自動で設定されます。

Multicast側のイベントからサウンドの再生処理を書いていきます。
Spawn Sound 2Dノードを配置します。
ここでは、必ずAtomカテゴリのノードを使用します。
Audioカテゴリの同名のノードはUEデフォルトのものですので、キューの再生ができません。

配置されたノードの「Sound」「StartTime」インプットピンからドラッグしてイベントノード上でドロップします。
イベントノードの入力ピンが追加され、外部から再生するキューと再生開始位置を指定できるようになります。
また、後でBGMを停止させたり、音量を調整したりできるよう変数として格納すると便利です。
これを行うにはSpawn Sound 2Dノードの「Return Value」、青いアウトプットピンを右クリックして「Promote to Variable」を選択します。

Server側のイベントノードからMulticastイベントを呼び出し、そのインプットピンからイベントノードにドラッグ&ドロップします。
Server側のイベントノードにも入力ピンが作られます。

次に重要な設定です。
アクターの「Class Defaults」を開き、Detailsパネルにて「Replicates」にチェックを入れます。
「Replicates」はこのアクターをネットワーク対応させるもので、これにより各種状態などが同期されます。
「Net Load on Client」にもチェックを入れましょう。
これは、レベル上に配置されたアクターを自動的にクライアントに同期する設定です。

ゲームをテストプレイしてみましょう。
レベルブループリントにキーを押したらイベントが呼ばれるような処理を書いてみました。

サーバー側でキーを押すと、すべてのプレイヤーに正常にBGMが流れるようです。
(画像では視覚化するため、Spawn Sound 2Dの代わりにSpawn Sound at Locationノードを使用しています)
しかしクライアント側でキーを押しても、サーバー側はおろかクライアント側ですらもBGMが流れません。

これは「BP_BGMManager」の所有権がサーバー側にあり、クライアント側からは操作できないようになっているためです。
プレイヤーキャラクター側でキー入力を受け取り、その場でBP_BGMMangerにイベントを送信することで解決します。
プレイヤーキャラクターのBPを開きます。
デフォルトではここにあります。

Run On Server属性のカスタムイベントを作り、レベル上の「BP_BGMManager」を探してServer_PlayBGMイベントを呼び出します。

キーを押したらこのイベントが呼ばれるようにします。

少し回り道をしましたが、クライアント、サーバー共にBGMの再生トリガーを引けるようになりました!

プレイヤーによって異なるサウンドを再生する
たとえば対戦ゲームなどではこのような状況が考えられます。
-
勝利チーム側と敗北チーム側で異なるジングルを再生する
-
味方の回復による効果音と敵チームの回復による効果音を分岐させ、戦況を分かりやすくする
-
キャラクターにTeam変数をもたせる
-
Switchタイプのキューでゲーム変数をスイッチさせる
-
Selectorラベルで分岐させる
-
今回はキューごとに分岐が容易なSelectorラベルを使用する
-
ひとつのキュー再生でチーム別のサウンド分岐が可能
AtomCraftでSelector分岐対応キューを作る
今回はプレイヤーによって異なるサウンドをスイッチタイプのキューで分岐させます。
対応するキューを作るため、AtomCraftを使用します。
新規にキューを作ります。
ワークユニットツリーのキューシートを右クリックし、「新規オブジェクト」→「キュー『スイッチ』の作成」を選択。

それぞれのトラックに分岐させたいサウンド(マテリアル)を配置します。

プロジェクトツリーの「ゲーム変数」を右クリックし、「新規オブジェクト」→「ゲーム変数の作成」を選択。

新規にゲーム変数が作られるので、名前をつけます。今回は「Team」としました。

キューを選択し、インスペクターの「スイッチ」を押してゲーム変数を指定します。

今回はチームによってゲーム変数を0,1で分け、0なら同チームのサウンド、1なら敵チーム用のサウンドが再生されるようにします。

ゲーム変数の初期値を変えながらテスト再生し、異なるサウンドが再生されることを確認します。

UEでサウンドを再生する
UEのエディタに移動します。
キューシートをインポートしておきます。
「基礎編」で作ったBGM再生イベントを改変して処理を作ります。
キャラクターにInteger型の「Team」変数を作ります。

Multicast_PlaySoundイベントノードに入力できる変数を追加します。
Integer型の「Team」です。

ノード間をドラッグ&ドロップし、Server_PlaySoundにも変数がリレーされるようにします。

サウンド再生時にSet Game Variable Value by Nameノードを使い、ゲーム変数を指定します。
ここでは入力されたTeam値がキャラクターのものと合致するか判定し、その結果によって同チーム用のサウンドまたは敵チーム用のサウンドが再生されるようゲーム変数の値を変化させます。

Server_PlaySoundの呼び出し時には、呼び出し元キャラクターのTeam変数を入力します。
これでサウンドの呼び出し側とサウンドの受け取り側の2キャラクター間でTeam変数が比較され、Switchタイプのキューのトラックが分岐することになります。

ここまでのブループリントグラフは、こちらからコピペできます。
補足
クライアントの干渉制限
ネットワーク対応イベントを作っていくと引っかかりやすいポイントです。
UE5におけるRPCは、基本的にプレイヤーに所有権のあるアクターのみ発動できます。
基本的に、アクターは大部分がサーバー所有のものとなっています。
レベルに配置されていたアクターや、ランタイムでスポーンしたアクターも同様です。
そのため、クライアント側のプレイヤーは大部分のアクターのイベントや関数を直接呼ぶことができません(一応呼ぶことができるが、その場合他のプレイヤーに反映されないためネットワーク対応とならない)。
クライアント側のプレイヤーからネットワーク対応のイベントを起こす場合、プレイヤーコントローラやプレイヤーキャラクターを経由するのが良いでしょう。
サーバーとクライアントで処理を分岐させる
アクターの所有権がどちらにあるか調べる場合はHas Authorityノードを使用すれば判別できます。
Has Authorityノードはサーバー側でのみTrueが返ります。

Switch Has Authorityノードも同様のはたらきをします。

これらのノードで処理を分岐させ、現在処理を行っているプレイヤーがサーバー側であればイベント発行、などのようにサーバー主体のイベント管理をしていきましょう。

