読者です 読者をやめる 読者になる 読者になる

Let's Enjoy Unreal Engine

Unreal Engineを使って遊んでみましょう

UE4 自作ゲームでのゲーム制作事例解説(後編)

前回はC88に出展した自作ゲームの事例解説をしました。

unrealengine.hatenablog.com

今回も引き続き、ゲームでの事例解説をしたいと思います。

前回はゲームのメインの進行管理を解説していましたが、今回はレベルの管理、UMGの扱いについてなど補助的な部分を扱ってみようと思います。

f:id:alwei:20150824150948j:plain

全体のレベル管理

まず今回はステージが複数ある前提のあるゲームなので、レベルの進行管理は当然複数ある前提で設計しています。レベルが複数ある場合に問題となるのはそのレベルの切り替え時です。上位レベル以外の下位にあるレベルは破棄されるとその情報を全て失います。ここで上手くやってあげないと画面の切り替えがおかしくなったり、BGMやSEが途切れたり等の問題が発生します。

幸いUE4には複数のレベルを同時に読み込むことが出来る仕組みが存在しています。これを上手く使ってレベルの切り替えを行なってあげましょう。全体の図としては以下のような状態になります。

f:id:alwei:20150824153909j:plain

まずメインレベル(パーシスタントレベルと呼びます)を作成し、その中に全てのステージを構成するサブレベルを突っ込んでおきます。そしてこれをゲーム中にストリーミングします。これをレベルストリーミングと呼びます。

docs.unrealengine.com

レベルストリーミングはゲーム開始後、サブレベルを自由にいつでも読み込む事ができます。もちろん破棄するタイミングも自由です。

エディター上では"ウィンドウ"→"レベル"のウィンドウを開くことによってレベルのストリーミング等の管理が可能です。

f:id:alwei:20150824154617j:plain

基本的にはパーシスタントレベルに全てのレベルを入れておき、必要なレベルを自由に管理します。レベル編集のロックや可視性のトグルなどもここで行ないます。

f:id:alwei:20150824154906j:plain

指定レベルを右クリックし、ストリーミング方法を変更する事によって、いつレベルを読み込むのか指定ができます。ここでブループリントを指定しておけば、ブループリント上で読み込むタイミングを指定する事が可能となります。

f:id:alwei:20150824155110j:plain

あとはパーシスタントレベルのレベルブループリント上で"Load Stream Level"を呼びます。ここでレベル名の指定以外に"Make Visible After Load"というフラグをチェックしておくと、読み込みが終了すると同時に指定のサブレベルの処理が走るようになります。読み込みが終了したら画面のフェードインなどの処理をさせて、突然パっと画面が切り替わらないような工夫もしておきましょう。

これでゲーム中に自由なタイミングでレベルをストリーミングロードできるようになります。当然ストリーミングは非同期読み込みですので、その間も別の処理、つまりローディングアニメーションを入れたりもできます。

リトライやステージの切り替え

当然レベルはリトライやステージの切り替えが必要です。まずリトライの場合は、単純にレベルをOpen Levelすればいいというものではありません。特にサブレベルのOpen Levelは禁止です。どうやら最悪ハングアップしてしまうようです。

基本的にはパーシスタントレベルをOpen Levelするか、"Reset Level"ノードを使います。Reset LevelはGame Modeから呼び出せるノードですが、その名の通り現在のレベルをリセットします。

もしリトライ処理をするのなら直前にGame Instanceクラス上にフラグを作り、Game Instanceにリトライをしましたという情報を保存しておきます。Game Instanceに関しては過去に解説をどうぞ。

unrealengine.hatenablog.com

あとはリセットされた時にEvent BeginPlayが呼ばれるので、その時にリトライかを分岐処理で判断しておきます。

f:id:alwei:20150824161212j:plain

これでリトライから来た場合には、諸々の処理を飛ばしていきなりゲーム画面に突入するようにフローを構築していきます。上手くいけばタイトル画面等を飛ばして、同じステージの内容を最初からやり直せるようになるはずです。

ステージ切り替えの場合も考え方は同じです。Game Instanceに次はどこへいけばいいのか情報を保持させておき、Load Stream Levelでレベルを読み込ませます。読み込みが完了した際に以前のステージのレベルは"Unload Stream Level"で破棄します。

これでリアルタイムのレベルストリーミングができるようになります。上手くいけばスムーズなレベル切り替えが出来るようになるでしょう。

UMGでちょっと苦労したところ

UMGは優秀なGUIまたはHUDの画面を作成するためのツールです。慣れればすぐにメニュー画面などは作成出来てしまうでしょう。

 実際このようなアニメーションなどもすぐに出来てしまいます。今回はスコアなども割り当てるためにGame Stateクラス上に情報を保存しておき、まとめて計算するという方式で表示させています。

f:id:alwei:20150824162631j:plain

複雑な計算式を必要とする場合にはMath Expression(数学式)ノードはとても便利なものですので、活用しましょう。

docs.unrealengine.com

問題はここからでした。UMGは現在4.8の段階でアニメーション内に音を仕込むことができません。更に再生しているアニメーションの現在時間も取得できません。これには少し苦労させられました。

f:id:alwei:20150824163037j:plain

少し残念なやり方ですが、再生を開始してからDelayノードで時間を置いてから順次音を再生させていきます。アニメーションを見ながら音が聴けるわけではないので、直感的ではないです。この部分に関してはUMGの改善ポイントだと思いますので改善に期待したいです。

UMGはActionやAxisイベントが使えない

これにも苦労させられましたが、UMG上ではActionやAxisによる入力イベントを取得できません。なのでメニュー周りの入力はかなり面倒です。今回のゲームでは、UMG内の"On Key Up"関数をオーバーライドし、その内部で"Gey Key"情報からどのキーを押しているのか全て保存する事にしました。

f:id:alwei:20150824163634j:plain

どのキーを押したかは全てBoolean変数として保存しておきます。

f:id:alwei:20150824163835j:plain

あとはEvent Tickで入力監視を行ない、押されたキーに応じた処理を行ないます。

しかしこの方法は汎用性こそあれ、スマートではないですし、Tickは処理がタイミング依存です。やはりキーを入力した瞬間のイベント送信するべきと思います。今回は時間の兼ね合いもあってこういう手段をとりましたが、もっと上手い方法はあると思います。

そしてできればUMGの入力周りももっとスマートに出来るようになってほしいですね。

ポーズ処理

最後にオマケですが、ゲームのポーズ処理(一時停止)に関してです。UE4はこの部分に関して、ポーズが出来るように最初から設計されています。

 やっている事は本当に単純です。

f:id:alwei:20150824164533j:plain

レベルブループリント上でポーズキーが入力されたイベントを取得し、ポーズ画面のUMG  ウィジェットブループリントを作成します。

f:id:alwei:20150824164703j:plain

あとはウィジェットブループリント内で"Set Game Paused"を呼ぶだけです。ポーズが終わったら、もう一度Pausedのフラグを外して呼び出せばポーズ終了です。

ね?簡単でしょう?

ちなみにポーズをかけてもUIはしっかりと動きますので、ご安心を。もし他に動かしたいアクターがいる場合には、アクターデフォルト値にある、"詳細"のTickから"Tick Even When Paused"のフラグにチェックを入れると、そのアクターのEvent Tickだけは動くようになります。

ゲームを作った人はどんどんノウハウや事例を公開しましょう

今回は補助的な部分が多かったですが、意外と知らない情報が多かった人も多いと思います。また制作した際の苦労話は確実にこれからの人のために役立つ情報となります。