ADX2 for UE4で、キャラクターボイスの同時発音数を制限する

# はじめに
アンリアルエンジン4とサウンドミドルウェア「ADX2 for UE4」を連携させ、**ゲーム内キャラクターボイスの同時発音数を制限**します。
さらに、それに伴う弊害である「同一キャラクターが複数存在している場合に全体で発音制限がかかってしまう」問題も解決してみます。

キャラクターがボタンに応じて3つの技を使い分け、それぞれに異なるボイスが設定されているシチュエーションを想定し、続けて技を発動した場合でもボイス再生が重ならないよう処理を書いていきます。

他にも、キャラクターボイスの差し替えテクニックを解説する過去記事があります。
**ゲーム中の複数キャラボイス管理テクニック(ADX2 for UE4)**
https://qiita.com/SigRem/items/6a4d46c8138ebd09b0bd


当記事ではUE4.26.1を使用します。基本的にブループリントのみでの実装を想定しています。
ADX2はインディー向けの「LE版」であれば、無料で使用できます。
https://game.criware.jp/products/adx2-le/

記事執筆時点のADX2 for UE4のSDKバージョンはv1_29です。

# 前提
ADX2 for UE4の導入や基本的な使い方は以下の記事にあります。必要に応じて参照してください。
ADX2 for UE4の導入で、一歩上のサウンド表現を（導入編）
https://qiita.com/SigRem/items/4250925f6d66a4fd287a
ADX2 for UE4の導入で、一歩上のサウンド表現を（実践編）
https://qiita.com/SigRem/items/c089b71c42e898980a46

## AtomCraftでボイスサウンドを用意する

### マテリアルのインポート
プロジェクトを開き、マテリアルツリーに音声をドラッグアンドドロップしてインポートします。
![A01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/095fd0ce-70f0-1cbe-3797-5f98ac2c6577.png)
今回はキャラクターが使用する必殺技を想定し、3つのボイスを用意しています。

### キューの作成
新規にキューを作成します。
ワークユニットのキューシートを右クリックし、「新規オブジェクト」→「キュー『ポリフォニック』の作成」を選択します。
![A02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/9611e06a-1b03-7517-669c-70f4d8a994ea.png)
3つの音声に対して、それぞれひとつずつキューを用意します。
![A03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/0ef35194-c752-3e53-aee9-0c42a2c27abf.png)
タイムライン上にマテリアルをドラッグアンドドロップし、キュー内で音声が鳴るようウェーブフォームを配置します。
![A04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/64b1a9f0-a758-83d1-3181-e7be09a8e9e7.png)

もしゲーム内で距離減衰を加味した再生をしたい場合、キューを選択した状態でインスペクターの「パンのタイプ」を「3Dポジショニング」に変更します。
![A05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/59d5b2a9-c86f-f94c-66df-926269c92dac.png)

### ボイスリミットグループ、カテゴリの作成・設定

キャラクターボイスの同時発音制限を行うには、「ボイスリミットグループ」か「カテゴリ」機能を使用します。
プロジェクトツリーの「ボイスリミットグループ」を右クリックし、「新規オブジェクト」→「ボイスリミットグループの作成」で新規にボイスリミットグループを作ることができます。
![A06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/7d415f6c-2de4-5074-6fdb-3b2227346c95.png)
分かりやすいよう名前をつけます。
デフォルトで作られている「VoiceLimitGroup_0」をリネームして使っても構いません。
![A07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/b50acea0-7574-7576-f6bf-7768e325b53d.png)
インスペクターにてボイスリミットグループの情報が確認・編集できます。
「ボイスリミット数」で設定された数だけ同時に発音することができます。通常一人のキャタクターには同時にひとつの台詞のみ喋らせたいので、ボイスリミット数は「1」にしておきます。
![A08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/10018447-7b28-69ea-8920-4871b62b6ae0.png)

音声にボイスリミットグループを設定します。
キューを開き、**ウェーブフォームを選択した状態で**、インスペクターの「ボイス」をクリックします。
![A09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/3e29a60d-140c-0ff4-b9b1-1b80bc3dea1e.png)
作成したボイスリミットグループを設定します。
![A10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/3d1b3ff0-b3f8-889c-3ab0-e4330daf7e27.png)
「ボイスプライオリティ」の項目で、先に発音されたボイスか後に発音されたボイスのどちらを優先して再生するかを選択できます。
優先されない状態のボイスは処理が走っても再生されなくなります。
![A11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/e3c282f7-0985-d515-a130-e217f0381b8e.png)
アクションゲームなどにおけるキャラクターのボイスは、ちょっとした掛け声は先着優先にして連続で再生されないようにし、必殺技などの重要なボイスは後着優先にし優先して再生するのがいいでしょう。

シチュエーションを想像してみると分かりやすいかもしれません。小さなパンチやキックなどの連続で繰り出す攻撃は、その度にボイスを発していては機械的で鬱陶しく感じることケースがありそうです。
逆に大技のボイスは見せ場なので小技のボイスの発声をやめてでも再生させたいところ。また、大きなダメージを受けた際のボイスも後着優先にして上書きして発声するといいかもしれません。

また、同時発音制限はカテゴリ機能でも実装することができます。
プロジェクトツリーの「カテゴリ」内にある任意のカテゴリグループに、カテゴリを作成することができます。
![A12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/d753e505-1ab9-060c-9033-9a193b71e418.png)
こちらもボイスリミットグループと同じように「カテゴリキューリミット数」で同時発音許可数を変更可能です。
![A13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/958ff7a0-947f-c735-ea0a-16dfb44b12d9.png)
カテゴリはボイスリミットグループと違い、キューに対して設定します。
**キューを選択した状態で**、インスペクターの「カテゴリ」をクリックします。
![A16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/bfc11b2f-7e3f-5d9d-f884-195fda568bf8.png)
カテゴリの編集ウィンドウが開くので、任意のカテゴリにチェックを入れます。
同カテゴリに属する音声は同時再生されなくなります。
![A17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/df3645da-6e84-c3dc-c342-1180998a8690.png)


### キューシートのビルド
ここまでできたらキューシートをビルドします。
![A14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/5c278a60-cd76-9189-a868-c5e3cd11dd29.png)
![A15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/dc0d2e4a-39fc-bc83-0bc0-7e882269f0e9.png)


## UE4でボイス発音制限を実装する

### キューシートのインポート
UE4エディタのコンテンツブラウザにビルドしたacf、acbファイルをドラッグアンドドロップしてインポートします。
![B01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/cf417ebb-4154-4ab9-94c8-d3c6e61cdeb6.png)
ツールバーの「Edit」→「Project Settings」でプロジェクト設定を開きます。
![B02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/943b3e3f-f4c1-0979-b48d-73bd56224beb.png)
CriWareタブの「Atom Config」にインポートしたacfファイルを指定します。
![B03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/3a7c9a83-9c37-cc88-0d38-7d31e39d1c60.png)
設定が完了したら**UE4エディタを再起動します（重要）**。
今回の発音制限処理はacfファイルから影響を受けるためです。


### サウンドのセットアップ
発音制限に関する処理を適用するため、ボイスを再生するキューを開き、「Apply Atom Parameter」のチェックを入れます。
![B04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/4869928c-c6fd-8279-837c-9ef1ab884cf1.png)
キューが多い場合、UE4の「プロパティマトリクス」機能を使うことで一括で編集ができます。
編集したいキューを選択し、右クリックして「Asset Actions」→「Bulk Edit via Property Matrix」を選択します。
![B05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/d73181bf-294c-3689-8330-5546877c960c.png)
プロパティマトリクスのウィンドウの右側で「Apply Atom Parameter」を見つけ、チェックを入れることで選択したキューすべてに設定が適用されます。
![B06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/faf093cc-5a2a-1df7-61bc-051868125959.png)

### ブループリントでボイスを再生する
テストのため、プレイヤーキャラクターにボイスを再生する簡単なイベントを作ります。
プレイヤーキャラのブループリントを開きます。
「+ Add Component」から、「Atom Component」を追加します。
![B07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/15e16497-7f70-d13b-58c5-c89f97f43244.png)
イベントグラフにて、「1」キーを押したらスキルのボイスが再生される処理を書きます。
使用するのは**Input Key 1**でキー入力を感知し、**Set Sound**ノードで再生するサウンドを指定します。最後に**Play**ノードで音声を再生するだけです。
![B08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/9f617b9a-3bd2-725c-9ef1-f6494c69bc43.png)
**Get Atom（コンポーネント）**ノードはコンポーネントをグラフ上にドラッグアンドドロップすることで配置できます。
![B10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/c31ec7a6-c763-5694-3a8e-aa8c2665c9ba.png)
同じ用に3つの技について、ボイスの再生処理を作ります。
これで1,2,3キーを押した際、それぞれ違うボイスが再生されることになります。
![B09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/5a5d3bd1-4639-2c72-55c8-f547bf3720b9.png)
再生してテストしてみると、AtomCraftで設定したボイスリミットグループによりボイスが重ならず再生されるはずです。
（今回はひとつのAtom Componentに対してその都度ボイスを設定しているため、この時点ではボイスリミットグループを設定しなくても同時には再生されません）

さて、ここで問題が発生します。同じ性能・ボイスを持つキャラクターが同時に存在している場合、同一のボイスリミットグループを持っているため、どちらかがボイスを再生するともう一方のキャラクターはボイスを再生できなくなってしまいます。
この現象を解決するため、「Atom Sound Object」機能を使ってみます。

### 同一キャラクターを実装
まずは同時に存在しているキャラクターをテストするため、ボイス再生テスト用のブループリントクラスを用意します。

コンテンツブラウザの任意の場所で右クリックし、「Blueprint Class」を選択します。
![B11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/1b62f6f9-3eeb-5b0f-d6f2-a82455807250.png)
今回使うのは音声の再生だけなので、親クラスは「Actor」。
![B12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/a3c52e35-d087-53da-5136-7ecf9c8c1e12.png)
適当に名前をつけます。
![B13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/60d5962e-d214-e94e-1004-c090df92625d.png)
ダブルクリックして開き、プレイヤーと同じようにAtom Componentを追加します。
![B14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/69c2da4f-70f8-47d9-9cf0-61f0f6f9aef1.png)
イベントグラフに移動します。
このアクターはデフォルトではプレイヤーの操作下にないため、**Enable Input**ノードを使ってキー入力などの操作を有効にします。
![B15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/df5ea404-edc0-58f1-61e4-1c692bf99f2a.png)
プレイヤーキャラと同じように、キーを押すことでボイスを再生する処理を書きます。こちらは4,5,6キーでそれぞれの技ボイスが再生されるようにしました。
![B16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/52ee2c11-21d0-b63d-fd54-83f53328edc7.png)

レベル上にこのアクターを配置するとテストが可能です。
この状態で1～6のキーを押しても、お互いのボイス優先再生権が競合してしまい片方のキャラクターしか発音できません。


### AtomSoundObjectを使い、全体発音制限を解決する
そこでAtom Componentに「AtomSoundObject」を指定する必要があります。
「AtomSoundObject」はボイスリミットグループなどの

コンテンツブラウザの任意の場所で右クリックし、「Miscellaneous（その他）」→「Data Asset」を選択します。
![B17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/3cefbd50-4a93-0c90-f189-2ca9a682d019.png)
データアセットのクラスは「AtomSoundObject」を選択。
![B18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/20b6e6ba-6cf1-171d-d073-258e46cbcfa9.png)
アセットが作成されるので、適当に名前をつけます。
![B19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/3d083654-47a7-25a4-525a-cf687887b054.png)
ダブルクリックして開きます。
「Enable Voice Limit Scope」「Enable Category Cue Limit Scope」というチェックボックスがあるため、同時発音制限に使用している機能の「ボイスリミットグループ」か「カテゴリ」のどちらかで該当するものにチェックを入れてください。
![B22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/3e9bcdcd-465d-25b0-1915-4edf9b535fee.png)

プレイヤーキャラクターとボイス再生用アクターが持つAtom Componentを選択し、Detailsパネルの「Sound Object」に作成したAtomSoundObjectを指定します。
![B20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/a3dffa53-e666-9ab7-b18d-6f89d84d6872.png)
![B21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/05f15497-01fd-313c-dd26-21e1e6f97b54.png)

ここでテストしてみると、プレイヤーキャラとボイス再生アクターはそれぞれ同時にひとつの台詞しか喋らず、かつお互いが同時に発声することが可能になっているはずです。

### 補足: 動的にAtomSoundObjectを作成する

ブループリントを使って、ゲームの実行中に出現するキャラクターへ動的にAtomSoundOjbectを適用することも可能です。
**Construct Object from Class**ノードを配置し、
![B24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/6f8cdd30-831a-be93-907a-102063a274c6.png)
![B25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/cd0eb690-f5ee-0a05-5f0d-3c36862f77ca.png)
「Class」には「AtomSoundObject」を指定します。「Outer」には**Get Reference to Self**ノードを配置しつなげます。
![B26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/6ee78a89-8852-932d-4ede-2b37d2ac4cbf.png)
**Set Enable Voice Limit Scope**、**Enable Category Cue Limit Scope**で発音制限機能の選択ができ、最後に**Set Sound Object**でAtomコンポーネントにAtomSoundObjectを適用すれば完了です。
![B23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/fa732272-6a0f-ed06-f1c5-8a9d42a47eff.png)