【UE4】キャラクターセレクト画面

<h2>スタート時のキャラクターを選べるようにする</h2>
前回、メニューを出してキャラクターを変えられるようにしましたが、
ゲームスタート時にも使うキャラクターを選べる画面を作りました。
https://qiita.com/KLaboratory/items/af3c63d7db4a0ccaaff7

それに伴い、スタート画面用のレベルと、メニューのウィジェット
メインレベルを作りました。
また、グローバル変数を格納するゲームインスタンスを作りました。
<h3>ゲームインスタンス</h3>
2つの変数を作ります。最初はActorクラスの配列。
デフォルト値に使用するキャラクターを入れます。今回は3つ用意しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588692/084ceeee-f521-d7c6-b5b3-9da37703f8d8.png)
もう一つは、配列のインデックスを取得する整数。デフォルト値は0。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588692/9e1b2b6b-9fc1-258e-3164-c3c832d7e520.png)
ゲームインスタンスはこれだけです。
これをプロジェクト設定のゲームインスタンスに設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588692/c2614775-b78f-1636-5c72-036897629a43.png)

<h3>スタート画面(ウィジェットBP)</h3>
スタート画面用のウィジェットブループリントを新規で作ります。
![start.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588692/1eac6b91-7681-c813-c2da-7918d758a2ac.png)
何も選択せずにスタートボタンをクリックすると、DefaultPawnの
![Erika.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588692/b521592f-99d1-8423-add0-6269025b5779.png)
が選ばれます。イベントグラフは簡単です。ゲームインスタンスのインデックスをセットするだけ。
これでゲームスタート時に使うキャラクターが決まります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588692/e2564243-5053-ed7e-83ca-40fff23034f8.png)
スタートボタンをクリックしたときにメインレベルを開き、
Quitボタンをクリックするとゲームが終了します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588692/56e22348-ff5a-c014-5f6a-7fbcd7d1cea7.png)

<h3>スタートレベル</h3>
スタートレベルを作ります。新規レベルでデフォルトを選んで作成したあと、すべてのActorを削除します。
なにもActorがないので、専用のゲームモードを作ります。
ブループリントには何も必要ありません。DefaultPawnClassをNoneにします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588692/313d8277-fdc7-b70c-c458-1c8cddb05650.png)
スタートレベルのワールドセッティングをこのゲームモードにします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588692/19e0d2c8-6abd-dc28-5383-f721494d2374.png)
※GameMode Overrideを「None」にしても今回は同じ挙動になります。
※ただ、他にもNoPawnのレベルを作るならばゲームモードを用意しておいたほうがいいと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588692/77582a09-d5c4-c759-1573-aabda3e9120d.png)
続いて、スタートレベルのブループリントですが、
ウィジェットを開いてカーソルを見えるようにするだけです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588692/05c7e803-d777-590e-bdc4-45ab9eb74da7.png)
<h3>メインレベル</h3>
ワールドセッティングは今までのゲームモードを設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588692/391c3967-016f-ce2b-b1cb-f57f089204f5.png)
レベルブループリントは以下のとおりです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588692/7a6faa2a-cc64-bb35-5232-a2813a681be3.png)
前半部分、ゲームインスタンスに記録されたインデックスが0以外になっていると、
デフォルトキャラクター以外が選択されたことになります。それを取得します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588692/ca4c83d0-3baa-6c7a-1e9c-ea91259f58ce.png)
後半は、デフォルトキャラクターをDestroyして、選ばれたキャラクターをspawnします。
これは今までの応用です。アクターの配列からインデックスを指定することで、
Spawnするキャラクターが決まります。
ただ、今まではそのままPossessに接続できましたが、一旦キャラクターにキャストする必要があります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588692/a9cdc449-92dc-df32-f85c-00e48d206a2f.png)

<h2>ゲーム途中のキャラクターを変える</h2>
<h3>3つ以上のキャラクターから選ぶ</h3>
前回までは2つのキャラクタを交互に替えていただけですが、
3つ以上のキャラクターを選べるようにしました。
<h3>キャラクターチェンジ画面(ウィジェットBP)</h3>
キャラクタチェンジ用ウィジェットブループリントを新規で作ります。
スタート画面と同じ要領ですが、背景は透明にして、Start、Quitボタンはありません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588692/3d19756a-fe5b-bf9c-c99c-b3f7e0668ec4.png)
続いてブループリントです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588692/726fb853-b7f8-0531-4c99-440353831243.png)
前半はスタートウィジェットと同じく、ゲームインスタンスのインデックスをセットします。問題は後半
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588692/395213c3-c621-e63c-f247-d75870f55059.png)
RemoveFromParentで、画面を消します。続いてSetInputModeGameOnlyでインプットはゲームのみで有効にします。
マウスカーソルを非表示にして、最後に<strong>イベントディスパッチャーを発行</strong>します。
これがないとうまくいきませんでした。詳しくはPlayerControllerで説明します。
<h2>PlayerController</h2>
今までの変身に加えたのですが、相当長い処理になりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588692/f6a7fd7f-1638-06d3-2761-ae8fd9fba4ca.png)
変身のコマンドが入力された瞬間、現在のキャラクターのインデックスを取得し、ローカル変数に格納します。
続いてウィジェットとマウスカーソルを表示させます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588692/d6564ba6-cfa6-47e4-5ff3-d72e6603bddd.png)
SetInputModeUIOnlyはウィジェット画面だけインプットが有効になるための処理です。
なので、先程のウィジェット消去画面で、ゲームにインプットを戻す必要があるのです。
SetGamePausedでゲームを止めます。そうしないと、メニュー選択の間にもゲームが動いてしまいます。
つづいて、ウィジェットから発行されたイベントディスパッチャーをバインドします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588692/a0ed77b3-6627-246b-6133-4735edd805a4.png)
カスタムイベントでイベントディスパッチャーからのイベントを受けます。
SetGamePausedでゲームを止まっているゲームを再開します。
メニュー画面が出た瞬間と、消えた瞬間でゲームインスタンスのインデックスの数字が
替わっていたら、キャラクターが替わっているので先に進みます。
同じキャラクターを選んだ(替えるのをやめた)場合は何もしません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588692/adcab172-3dd7-e63f-48fd-f92384d76e6b.png)
アクターをDestroyして、新たにSpawnActorをします。今回はスタート時のキャラクターが
どれかわからないので、0(デフォルト)であるかどうかを判定する必要はありません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588692/fb1034b9-1891-be19-5119-14dc4b3f2627.png)
<h3>イベントディスパッチャーを何故入れるか</h3>
実は私も理由がまだわからず教えて欲しいところでもあります。ただ、こうしないと、
<strong>画面が止まったまま、キャラクターだけが入れ替わる</strong>
ということになります。SetGamePausedは入力や画面は止まるけど、
内部の処理は止まらないのではないでしょうかね？それをイベントディスパッチャーでせき止める。
そんなイメージではないかと思っていますが、ご存じの方がいらっしゃったら教えて下さい。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">キャラクターセレクトメニューを作る。<a href="https://twitter.com/hashtag/UE4?src=hash&amp;ref_src=twsrc%5Etfw">#UE4</a> <a href="https://twitter.com/hashtag/UnrealEngine4?src=hash&amp;ref_src=twsrc%5Etfw">#UnrealEngine4</a> <a href="https://t.co/Y4TpXKPWW7">pic.twitter.com/Y4TpXKPWW7</a></p>&mdash; 特命社長 (@tokumeishatyo) <a href="https://twitter.com/tokumeishatyo/status/1261994755069632513?ref_src=twsrc%5Etfw">May 17, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>