VRMを使ったゲームを仕上げでみよう
VRMが領域に入ったら音声を発生するようにしてみよう
レベルに配置しているVMC用のVRMキャラクターにタグを追加します。

次にBP_VMCCharacterを開くとコリジョンがNo_collisionになっているので、OverlapAllにしてGenerateOverlapEventsにチェックします。
(壁にぶつかってほしくないが重なっているイベントは発生して欲しいため)

次に右クリックしてブループリントインターフェイスを作成します。
名前はBPI_Voiceにしてみます。

関数名をVoicePlayにしてインプットの1つ目の名前をVoiceWaveにして型をSoundWave型、2つ目の名前をVoiceTextにして型をStringにしコンパイルし保存します。

今回キャラクターとして使っているBP_VMCCharacterのブループリントを開きクラス設定を押し実装インターフェイスに先程作ったBPI_Voiceを選びます。


コンパイル後、マイブループリントのタブのインターファフェイスのところで関数が選べるようになっているので中身を実装します。

与えられた音声を発信して発信中は一定間隔でイベントが起きるというものを書きます。一定間隔で実行するものには口パクのモーション再生を入れます。(まばたき参照)

音声を発生する領域を作成します。今回はその範囲がわかりやすいように半透明のBOXを作成します。
とりあえずマテリアルを作成してblendModeをTranslucentにします。
1を押しながらマウスクリックして値を0.5にしてオパシティにつなぎます。

BOXをアクターとしたブループリントをBP_box1という名前で作成し中に入ります。
Cubeを追加しマテリアルを半透明のものにします。
音声(Sound Wave形式)とテキスト用2つの外部から参照できる変数を用意し。Cubeのオーバーラップ時のイベントに入ります。

まず、重なったものがVMCのキャラクタかタグで判断し、問題なければ
作成したブループリントインターフェイスBPI_VoiceのVoicePlay関数で音声を出す機能を呼び出します。

音声の文字表示のUIを作ろう
次に字幕表示用のUIを作ります。名前はUI_Talkあたりにします。

キャンバルパネルを全体borderを下の方に配置します。

次にテキストを以下のように設置し右上のisValidにチェックをつけコンパイルし保存します。

グラフに移動して下図のようなウィジェットにパラメーターのテキストを
表示するようなロジックを組みます。

BP_VMCCharacterのbeginPlayのまばたきを実装した箇所の前にウィジェットを作成し変数に格納する機能を追加します。

次に口パクをするロジックのブループリントインターフェイス版の開始時にウィジェットを表示する機能を追加します。

この段階でちゃんと動作するかテストします。
レベルに作ったBP_box1を配置しPlayInで実行しF8を押します。
BP_box1を選択し、キャラクターにぶつけます。
音声と字幕が出れば成功です。

音声を出す箱を連続的に作って定期的にしゃべらせてみよう
ではゲーム3秒毎に音声を聞いて1秒以内にポーズを取ってスコアを競うゲームを作ることにします。
音声なのであいまいな判定もOKとします。
まず、レベル上のキャラの近くにスポーンするポイントを配置します。
当たると音声を発する箱にProjectileMovementを追加し、スピード3000、重力の影響を0にします。

レベルプループリント上にパラメータで音声を発生する箱をスポーンする関数を作ります。

関数のパラメータ以下の通りにします。あとの2つは判定用のフラグです。

とりあえず、ランダムで数種類の音声を出すように以下のようにプログラムします。
注:ゲーム開始前に色々飛んできても困るので両手を上げるまでゲームはスタートしないようフラグで分岐しています。

自分が動かないと画面が停止していてつまらないのでランダムにカメラを切り替える機能も追加します。先に作っていたカメラをtagで切り替える関数を利用します。
パラメータはtagの配列にすることにより。前の方多めなど見栄えのよいところを多めにすることもできます。

作った関数をBiginplayで3秒毎に呼び出すように設定します。

音声とモーションがあっていれば点が入る仕組みを作ろう
左右の手の上げ下げ判定用の関数を作成します。サイリュームのソケットの位置と、音声を出すために付けたオーディオコントロールの位置を比較して上下を判定します。口の位置だと結構厳しいと思うので微調整できるように定数も足せるようにしておきます。PlayerOneはレベルのBeginplay時に変数化したキャラクターです。
ソケットの位置を取得する関数は構造化ピンを分割しておきます。


キャラクターのブループリントの音声を発生する関数の音声発生終了直後にスコア判定判定しても良い事がわかるためのフラグを立てます。


次に判定結果を表示する内容をスタートのときに作ったUMGにカスタムイベントを以下のように組み込みます。

まず、ミスしたらミスの表示とミス音を鳴らし、3回ミスしたらゲームオーバーになる関数を作ります。

点数チェックの関数を作成します。まず、現状のサイリュウムの上げ下げの関数を通したあとにデバッグ用の表示をします。

手の判定は位置が指示されていない場合はサイリュウムの位置がどちらでも正解、指示されている場合は同じでなかればミスに分岐する。
左手も同じ考え


判定が終わったらコンボ数とスコア(コンボ数☓100点)を表示し、スコアチェックをOKにした後に正解音を鳴らす。

正解した時に背後に〇の形のパーティクルが出るようにしよう
一応ゲームのループを作ったのですが、正誤が音でしかわからない為、味付けとして正解したときに○の形のパーティクルが出るようにしましょう。
まずはモデリングモードで以下ようなシリンダーを2つ作りましょう。


図のように2つのシリンダーが重なるように置き、2つのオブジェクトを選択して、VoxOpsグループのVoxBoolを選び承認するとくりぬかれて〇の形状ができます。

このままだと使いづらいので手前に90度回転し、下が地面のすれすれになるように動かしてTransformグループのBakeRSで回転をメッシュに保存しましょう。

次にのPivotを推しボックスボジションでBottomを選択して承認しましょう。また、

作ったメッシュを虫眼鏡で探し名前を付けて保存します。

適当なナイアガラを作成します、
スポーンバーストにして一気に沢山出して

スケルタルメッシュのロケーションを追加して〇のメッシュを設定し、1秒くらいで消える青色にします。
よくわからない場合は人が光のパーティクルになる動画を探しましょう。その中でスケルタルメッシュ用の関数を呼んでいるのはスタティックメッシュ用の置き換えているだけです。

ゲームオーバー演出を作成しよう。
とりあえず、今回VMCを送信しているアプリに終了時にとらせたいポーズをさせます。
※ゲームプレイし、VMCと接続できている状態にしておきます。
UE5に戻りVRM4Uのプラグインフォルダから「ABP_VRoidVMC_Bone」を検索し開きます。

アプリから送られたポーズが再生されている事を確認し、録画ボタンを押します。
ダイアログが出てきますので名前をつけてOKを押します。
そしてすぐに録画を停止します
※停止ボタンは録画を開始すると録画ボタンのちょっと上に出てきます。
今回は一部界隈で流行っている「手をついて詫びる」のポーズを一つ、やり遂げた時のポーズを一つ保存します。


レベルにおいたカメラを複製し、お詫びのポーズが良く映る位置に調整しtagsにdogezaとつけます。

次にミスしたときにお詫びのアニメーションをさせカメラを先程作ったカメラに切り替えるようにします。

次にポーズの確認処理を10回以上できたら勝利のポーズをつけ、カメラを正面にするゲームオーバー処理を入れます。
