はじめに
アンリアルエンジン4とサウンドミドルウェア「ADX2 for UE4」を連携させ、ゲーム中の会話パートにおけるボイスの再生及び再生待ち機能などを実装してみます。
普通にボイスを再生するほか、ボイスを再生し終わったらページ送りを促すアイコンの表示や、オートで会話を送っていく機能を追加します。
実装は基本機能編に処理を足していきますので、まずはそちらの記事をご覧ください。
https://qiita.com/SigRem/items/4ddb00da98062021344b
当記事では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
実装
メッセージ、ボイスを登録しておき連続で再生する
複数のメッセージとそれに対応するボイスを変数に記録しておき、プレイヤーが決定ボタンを押した際に次のメッセージ、ボイスを再生する機能です。
「再生リスト」としてメッセージ、ボイスをそれぞれ変数配列に格納し、ボタンを押すごとに次の配列を参照していく実装になります。
専用の構造体(Structure)を作成します。これは複数の変数をひとつにまとめておけるものです。
「1メッセージ」という単位にテキストとボイスをまとめてしまいましょう。
コンテンツブラウザの適当なところで右クリックし、「Blueprint」→「Structure」を選択します。
適当に名前をつけます。
ダブルクリックして開くとこんな画面になります。
「New Variable」ボタンを押して変数を追加します。
ふたつの変数の型を、それぞれ「Text」「Sound Atom Cue」にします。色が画像と一致しているのを確認しておくとミスがないかもしれません。
構造体が用意できたところで、基本実装編で簡単に処理を作った「BP_TalkManager」を改変していきます。
「My Blueprint」パネルの「+Variable」ボタンを押して変数を追加します。
新しい変数の型を先ほど作成した「Str_Message」にします。名前もつけておきましょう。
「Variable Type」の右にあるアイコンをクリックして「Array」に変更します。9つのキューブが集まっているアイコンです。
カスタムイベント「NewMessage」の処理を切り離します。ピンにマウスカーソルをあわせてAlt+左クリックで線を切ることができます。
メッセージ送り用のカスタムイベント「NextMessage」を作成します。
一連の処理は「NextMessage」の近くに移しておきます。
変数リストからドラッグし、Get MessageListノードを配置します。
線を引き出してAddノードを追加します。
Addノードの下側のインプットピンを引き出してMake Str_Messageを配置します。
ここに「Str_Message」が持つふたつの変数のそれぞれの要素を代入することができます。
カスタムイベントNewMessageから線をつなげます。
これで新しいメッセージ、ボイスを受け取ったら「Str_Message」の配列に追加されるようになります。
このイベント単体では再生されません。
カスタムイベントNextMessage側に同じようにGet MessageListを配置し、線を引き出してGetノードを置きます。これは配列内の指定されたインデックスを参照するものです。一番上のインデックスを参照したいので、番号は「0」にしておきます。
Get 0ノードからさらに線を引き出し、Break Str_Messageノードを作ります。これはMakeノードの逆で、「Str_Message」から要素を取り出していくイメージが分かりやすいかもしれません。
それぞれのピンを対応するノードにつなげます。
メッセージ送りをして新しいメッセージを表示したいので、これらの処理の前に前のメッセージを削除しなければなりません。
Get MessageListから線を引き出してRemove Indexノードを使用します。
レベルブループリント側で、キー入力に応じてNextMessageイベントを呼び出すノードを追加します。
この例ではゲーム中に「1」「2」キーを押すとメッセージとボイスが蓄積され、マウスを左クリックすると順番に再生されていくようになります。
ところが、2つ以上メッセージを蓄積しないと文章が表示されなくなってしまいました。
これは、カスタムイベントNextMessageが強制的に0番のインデックスを削除しているためです。
これを解決するために少し改良を加えます。
カスタムイベントNewMessageに次のようなBranchを追加します。
これは配列変数「MessageList」の0番目が現在有効かを調べるものです。
もし何も代入されていない場合、結果は「False」に分岐します。
「False」側では次のように処理をつなげます。
少し複雑になりますが、すべて正しく接続されているか確認してください。
これで0番のインデックスに何も入っていない(=最初のメッセージである)場合、インデックスの削除が行われずメッセージが表示されるようになります。
ボイス再生終了時にアイコンを表示する
ボイスを最後まで再生した際、ページ送りが可能なことを示すアイコンを表示します。
予めUIウィジェットにアイコンの画像を追加しておきます。
サンプルとしてカスタムイベントを追加し、その際にアイコンが表示されるアニメーションを再生するようにしました。
アクター「BP_TalkManager」を開きます。
Event Tickに処理を追加します。ノードがない場合は新規に追加してください。
「Components」パネルからGet Atom Componentを配置し、線を引き出してGet Statusを配置します。
これはAtomコンポーネントの再生状態を取得できるノードです。
さらに線を引き出して「==」と検索し、Equal(Enum)を選択します。
Branchを配置してつなげ、Equal(Enum)で「Play End」(再生終了状態)を選択します。
UIのアイコン表示用カスタムイベントを呼び出します。
このままでは再生終了状態では無限にカスタムイベントが呼ばれ続け、アニメーションも正常に再生されないのでDoOnceノードを挟みます。「True」「False」の分岐をそれぞれ次の画像のようにつなげます。
再生終了時にアイコンが表示されるようになりました!
しかし、次のメッセージが表示されてもアイコンが出たままなのでこれを非表示にする処理を追加します。
Play Animationの「Play Mode」から線を引き出して、UIのカスタムイベントにドラッグアンドドロップします。
カスタムイベントが変数を参照できるようになります。
ふたたび「BP_TalkManager」に戻ります。
Next Messageの処理の最後にカスタムイベントを追加し、「Play Mode」を「Reverse」にします。
これでメッセージ送り時にアイコン表示アニメーションが逆再生され、アイコンが非表示になります。
オート再生機能
ボイスを最後まで再生した際、次のテキストとボイスを再生します。
アイコン表示処理に少しノードを追加するだけで実現できます。
新規に変数を追加します。型は「Bool」です。
これは自動でメッセージ送りをするオートモードが有効であるかどうかを格納する変数です。
Branchノードでオートモードかどうかを判断します。
オートモードが有効な場合、DelayノードをはさんでカスタムイベントNextMessageを呼び出します。
Delayで1秒程度待機をすることで、会話に「間」が生まれて自然な印象になります。