会話シーンを作成したい!
本作品では、以下のような会話シーンを実装しています。
ゲーム画面に覆いかぶさる形でUMGによる会話シーンが表示され、左右から会話するキャラクターがスライドしながら登場し、会話とそれに合わせたアニメーションが再生されます。
また、ローポリなので分かりにくいのですが、ゲーム画面に対して会話シーンのキャラクターはトゥーンシェーダーのようなアニメ調な見た目をしており、2Dイラストでの会話シーンのようなものを目指してみました。(2Dの絵は描けないし、2Dをアニメーションさせるのは面倒なので、ここは3Dと2Dの融合という感じです)
このような会話シーンの作成方法を解説していきます。
会話シーン設計
今回の作品では、ステージが始まると「開始会話シーン」→「ゲーム本編」→「終了会話シーン(成功 or 失敗 or 逮捕」が基本的なゲームの流れとなっていて、他にも任意のタイミングで会話シーンを差し込むことが出来るようになっています。
ということで、色々な場面で会話シーンを呼ぶことになる為、会話パラメータを渡しただけで、勝手に会話シーンが始まってくれるような仕組みを作る必要がありました。
その時、思い出したのは、Qiita UnrealEngine(UE) AdventCalendar 2021でのおかずさんの記事でした。
いきなり、このレベルの実装をしても路頭に迷いそうだったので、まずは自分で理解できる範囲で作ってみることを目標に、今回のゲームの内容的に必要な部分として、以下の機能のみを実装することにしました。
- 同時会話人数は2人まで
- 選択肢機能は実装しない
- アニメーションはアニメーションモンタージュのみを使用
- 多言語化は考慮しない
- スキップ機能は実装する
これを前提に、会話シーンに必須と思われる項目を集めてみたところ、会話パラメータとして必要なものは、以下のようなDataAssetとDataTableの組み合わせとなりました。
こちらが、会話用のデータアセットです。画面の左右にそれぞれ配置したいキャラクターの名前とキャラクターBPを入れられるようになっており、会話データが格納されたデータテーブルを保持しています。
そして、会話データはデータテーブルになっていて、「左右どっちのキャラが」「なんて喋って」「どんなアニメーションモンタージュを再生する」を連続で指定しているだけです。
必要最小限ですが、これで会話シーンの元となるデータを作成できそうす。
UMGにスケルタルメッシュを表示したい
そもそも、UMGにスケルタルメッシュを表示する方法すら分かっていなかったのですが、上記のおかずさんの記事を見てSceneCaptureComponent2Dには、必要なオブジェクトだけを撮影する機能がある事を知りました。(例えば、StaticMeshだけとか、StaticMeshとSkeletalMeshを撮影したい等が可能)
会話シーン用の舞台みたいなものを作成し、そこにSceneCaptureComponent2Dを2つ配置して、会話したいキャラクターを横並びにしてあげれば、UMG用のキャラクター画像は取得できそうです。
早速そのような舞台を作ってみました。名前はActorを継承したBP_Conversationとします。
ここで重要なのは、SceneCaptureComponent2Dのカメラの設定で、スケルタルメッシュのみを描画するように設定します。具体的には、下記のように設定しています。(色々なチェックを入れたり・外したりしてみて、試してみると面白いかもしれません)
そして、SceneCaptureComponent2Dには描画ターゲットが必要になりますので、左右のキャラクターをレンダリングする為に、2つの描画ターゲットを作成します。作成後、舞台に設置したそれぞれのカメラの描画ターゲットを設定します。
最後に、描画ターゲットから、UMG用のマテリアルを作成します。
これも凄く簡単です。新規にマテリアルを作成し、マテリアルドメインを”UserInterface”に変更し、ブレンドモードを”Masked”に変更しただけで、後は以下のようにノードを組むだけです。
これでSceneCaptureComponent2Dで撮影した画像をUMGで表示できるようになりました。
最後に会話シーン用のUMGを作成します。
SceneCaptureComponent2Dで撮影したキャラクターを左右からスライドして表示しているので、一旦枠の外にキャラクターを配置しておいて、会話シーンスタートと同時にスライドさせるようにしています。
これで、表示の仕組みが完成しました。
メッセージ表示ロジック
最後に、上記で作成したBP_ConversationにBPでロジックを組んでいきます。
まずは、BP上に登場させたキャラクターが残ってしまうことを防ぐ為に、初期化関数を作成します。処理としては、左右に登場させたスケルタルメッシュを削除するだけです。
次に、会話シーンを開始するカスタムイベントを作成します。
引数には、設計段階で作成した会話データを受け取るようにします。
左右のスケルタルメッシュを動的にスポーンします。CustomDepthの設定をしていますが、これは結局使いませんでした。
上記で作成したUMGを表示し、左右からキャラクターをスライドアニメーションで表示させます。
会話処理の実体です。会話データを1件ずつ取得しながら、指定されたキャラクターにアニメーションモンタージュを再生させつつ、UMGに会話メッセージを入れ込んでいます。処理は長ったらしいですが、読んでみると大した事ないはずです。
次の会話メッセージ表示と、メッセージスキップ用のカスタムイベントを作成し、処理に組み込みます。
次に、UMG側の処理を記述します。UMG側では渡された会話メッセージを一文字ずつ表示する機能の実装となります。改行に対応する為に、SetMessageカスタムイベントでは、渡された文字列の\nを改行に置換しています。
これで処理は完成です。
レベル上にBP_Conversationを置いてみる
おかずさんの記事では、Subsystem経由で会話BP(BP_Conversation)を動的に生成していますが、今回は説明を簡単にする為に、レベル上に直接置いてみます。
会話用の舞台が設置されました。本来であれば、ゲーム中に存在してはいけないものなので、どこか遠くの座標にでも飛ばしておいてください。
設計に従って会話データを作成した後に、レベルブループリントに以下に会話シーンを開始するロジックを組みます。今回はZキーを押したら会話シーンが始まるようにします。会話のスキップはスペースキーです。(GetAllActorsOfClassは今回の説明の為の処理です。これは処理が重たいらしいので、何度も呼ばないようにしてください)
これで、プレイして、Zキーを押してみましょう。
画面上に会話するスケルタルメッシュが表示されるはずです。
今回はBP_Conversationを見える範囲でレベル上に置いたので、会話シーンの撮影場面も見えてしまっています。
次回
次回の振り返り記事は、ゲームの設計での「簡略化」について振り返ります。よろしければ、次回もお付き合いください。
No responses yet