はじめに
ADXアンバサダーとして記事を書いておりますSigと申します。
この記事ではUE5とADX for UEを連携させ、マルチプレイヤーゲームにおいて、途中参加したプレイヤーにもBGMを同期するテクニックについて紹介します。
同じBGMが同じタイミングでかかっていることは体験の共有としてとても重要なのですが、途中参加したプレイヤーに対して同じBGMを同じタイミングでかけるには多少の実装が必要になります。
また、BGM同期にはADXのブロック再生機能を使用することで、
- ゲーム参加時はイントロが流れ始める
- 違和感のないタイミングで他プレイヤーと同じブロックに再生移行する
といった流れを踏み、途切れを感じさせないような実装が実現できます。
ブロック再生について、詳しくはこちらの記事を参照ください(当記事だけでも実装は可能です)。
やること
- BGMを構成する
- UEでマルチプレイヤーにおけるBGM再生を実装する
- 後から参加したプレイヤーにも同じBGMを再生する
- サーバー側で再生中のBGMのフレーズを取得し、すべてのプレイヤーに同期する
また、記事中に「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の導入で、一歩上のサウンド表現を(実践編)
基本的なネットワークゲーム(マルチプレイヤーゲーム)のサウンド実装については次の記事で解説しています。
マルチプレイヤーにおけるBGMの同期を実装する
AtomCraftでBGMを構成する
音素材を用意し、AtomCraftのマテリアルツリーにインポートします。
画像ではフレーズごとに素材を分割していますが、ひとつなぎの素材でもブロック再生の設定が可能です。

キューシート内にキューを作成します。
キューシートを右クリックし、「新規オブジェクト」→「キュー『ポリフォニック』の作成」を選択します。

キューを作成したら、時計のボタンから「タイムベースの編集」をしておくとブロックを配置しやすいです。

BPMなどを設定しておきます。

マテリアルを配置し、BGMを構成します。

トラックリストの空欄で右クリックし、「新規オブジェクト」→「ブロックの作成」を選択します。

ブロックが作られました。必要に応じて増やしたり、尺を調整します。

テスト再生中に他のブロックをクリックすると、ブロックの切れ目まで再生してから該当のブロックに移行、という動作が確認できます。

ここまでできたらキューシートをビルドします。


UE5でマルチプレイヤーのBGM同期を実装する
キューシートをインポートする
UE5のエディタに移ります。
ビルドしたacbファイル、acfファイルをコンテンツドロワー内にドラッグ&ドロップしてインポートします。
その際に表示されるダイアログでは、Yesを選択します。これにより、プロジェクトで使用するAtom Configファイルが自動的に設定されます。

Atom Configとキューシートのアセットが作られます。

キューシートアセットを開き、正常に再生できることを確認します。

マルチプレイヤー対応のBGMを再生する
BGMを再生するためのアクターを作ります。
こちらの記事で作ったアクターを再利用できますが、もし作っていない場合でも実装手順を簡易に紹介いたします。
新規にブループリントアクターを作ります。親クラスは「Actor」です。

次の画像のようなグラフを作ります。
RPCを通して、BGMとなる2Dサウンドを再生するBPです。

これで全員に同じBGMが再生されるわけですが……
BGMが再生されている状態で後から参加したプレイヤーからは、どうやら何も再生されていないようです……。

(遅れて参加した右下の画面のプレイヤーからはBGMが再生されていない)
上の画像では、視覚化しやすいようSpawn Sound at Locationノードを使用しています。
プレイヤーの参加を検知する
これを解決するため、まずはプレイヤーが参加したことを検知する仕組みを作ることにしましょう。
検知にはGameModeを使用しますので、自前でGameModeを用意してみましょう。
コンテンツドロワーで右クリックし、「Blueprint」→「Blueprint Class」を選択します。

下部の「ALL CLASSES」から「GameMode」を検索し、選択します。

新しくGameModeが作られました。分かりやすい名前をつけます。

ダブルクリックして開きます。
基本的なクラスをDetailsパネルで設定します。とりあえずは「Player Controller Class」と「Default Pawn Class」を設定しておけば動きます。

Event OnPostLoginイベントノードを配置します。
これはプレイヤーが参加した際に呼ばれるイベントです。

テストとして、Print Stringでプレイヤーが参加した表示をしてみましょう。

使用するGameModeをマップから指定します。
ツールバーの「Window」→「World Settings」を表示させます。チェックがついていればOKです。

World Settingsにて、「GameMode Override」を設定します。

プロジェクトのデフォルトのGameModeとして使いたい場合は、プロジェクト設定のMap&Modesから設定できます。

ゲームを再生してみると、プレイヤーの参加ごとにログが表示されるようになりました。

後から参加したプレイヤーにも同じBGMを再生する
プレイヤー参加検知の仕組みを使って、後から参加したプレイヤーにも同じBGMを再生してみましょう。
作成したGameModeを開き、My Blueprintパネルで「Event Dispatchers」を追加します。
「ED_PlayerJoined」と名前をつけました。
これは他のアクターなどから特定のタイミングを検知するためのもので、「ED_PlayerJoined」が呼ばれると外部からもそれをトリガーとしたイベント発火が可能です。

イベントグラフにドラッグ&ドロップし、「Call」を選択します。

線をつなげれば、プレイヤー参加時に「ED_PlayerJoined」が呼ばれるようになります。

BGMマネージャーのブループリントアクターを開きます。
Event BeginPlay時に、Cast ToでゲームモードへCastします。

Bind Event to ED_PlayerJoinedノードを使い、ゲームモード側で「ED_PlayerJoined」が検知された際のイベントを登録します。

プレイヤー参加時のイベントとして、新規にカスタムイベントを作ります。名前は「OnPlayerJoined」としました。

Bind Event to ED_PlayerJoinedノードの赤いインプットピンから線を引き出し、Create Eventノードを配置します。また、対象のイベントにOnPlayerJoinedを指定しました。
イベントに引数などを設定していると選択肢に出てこないため、その場合はOnPlayerJoinedがまっさらなカスタムイベントになっているかを確認しましょう。

さらにカスタムイベントを作ります。名前は「Server_SyncBGM」とします。
「Server_」とついているとおり、これはサーバー側でのみ実行されるイベントとなります。

OnPlayerJoined→Delay→Server_SyncBGMといったイベントの流れを作ります。
プレイヤー参加の検知と同時に処理を行ってしまうと、途中参加した側のプレイヤー画面ではロード中などでうまく処理が行われないことがあるため、Delayノードをはさんでいます。

Server_PlayBGMイベントに処理を加えます。
「Sound」のピンを右クリックし、「Promote to Variable」で変数化します。

再生するBGMのキューを変数「BGMCue」として記憶しました。

Multicast_PlayBGMからは、「すでにBGMが再生されていれば新規に再生しない」という条件分岐を追加します。
BGMの重複再生を防ぐためです。

Server_SyncBGMイベントからServer_PlayBGMイベントを呼び出します。
サーバー側では初回BGM再生時にキューが記憶されているため、それを再生するBGMキューとして指定します。

これでようやく、途中参加したプレイヤーにも同じBGMが再生されるようになりました!

BGMのブロックを同期する
ADXのブロック再生機能を使い、違和感のないBGM同期を実装してみましょう。
BGMマネージャーのブループリントアクターを開き、新規にカスタムイベントを作成します。
イベント名は「Multicast_SyncBGMBlock」としました。

イベントノードを選択して、インプットピンを追加します。
型はIntegerとし、名前は「NextBlockIndex」です。

イベントでは指定したブロックを次の再生ブロックとするSet Cue Next Block Indexを使用します。
BGMが再生中かつ他のプレイヤーと再生しているブロックが不一致の場合、ブロック同期を行います。

Server_SyncBGMでBGMを再生した後に、Multicast_SyncBGMBlockでブロックを同期します。

これで途中参加側のプレイヤー側では、「ゲーム開始時にイントロが流れ始める→イントロを経て他のプレイヤーと同じフレーズが再生」といった同期処理が実現することになります。
補足ですが、Set First Block Indexを使うことで、再生開始時からいきなり指定したブロックを再生することも可能です。

「BP_BGMManager」のイベントグラフはこちらから参照できます。