Unreal Engine 4.25 でゲームの一時停止、再開、初期化、終了(Pause, Resume, Reset, Quit) を実現する

ゲーム中に何らかのキーを押すとゲームが中断してメニューが出て、ゲームをやり直すか、再開するか、終了するかを選べるメニューが出る、みたい機能を実現する方法をまとめたものです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/f161ee75-2b0d-65ab-4b10-4c3c844b7679.png)


あくまで最低限の処理しかしてません。

# 参考

- [ゲーム内の一時停止メニューの作成 / スクリプティング](https://docs.unrealengine.com/ja/Engine/UMG/QuickStart/5/index.html):公式記事
- [UE4 ゲームを終了する（Quit Game）](http://kagring.blog.fc2.com/blog-entry-126.html)
- [UE4 ゲームポーズを実装する（SetGamePaused、IsGamePaused）](http://kagring.blog.fc2.com/blog-entry-177.html)
- [[UE4]UMGのNavigation機能を使ってみる](https://historia.co.jp/archives/8521/)

基本的には上記の記事の内容を組み合わせて実現しています。いつもながら、えらい人たちに感謝します。バージョンの違いなどで動かない部分にも手を入れてます。

# 前提

- UnrealEngine 4.25 (多分 4.24 でも動きます）
- ThirdPerson のテンプレートを使っています。

# 方針

Qキーを押したらゲームを中断して、下のようなメニューを出します。

- Resume ボタンを押すと、メニューが消えてゲームが再開します。
- Reset ボタンを押すと、ゲームは起動した直後の状態にリセットされて、その状態から再開します。
- Quit ボタンを押すと、ゲームは終了します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/d9a1e680-4a78-117a-0997-0880afeba81c.png)

以下、ThirdPersonExampl テンプレートでProject を作成したところからの手順を書きます。

# ポーズしたときに表示されるメニューを作る

表示されるメニューの Widget をまず作成し、次に Q キーを押したら Widget が表示されるようにします。

## メニューの Widget の作成

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/96cc9ad3-8b48-6099-2017-b69ba8aa5b04.png" width="60%"/>

コンテンツブラウザで右クリックして、ユーザインタフェースからウィジェットブループリントを選ぶ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/51d0331e-1713-0a3c-19c7-60cd7f5d4fc4.png)

NewWidgetBlueprint という項目ができます。あとでこの名前を参照することがあるので、わかりやすいように MainMenu という名前に変更しておきます。以下、MainMenu という名前で Widget を作成したものとして説明します。

## ボタンの配置

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/426affc0-99a3-dd9c-bfea-c65a62d00c83.png)


コンテンツブラウザにできた MainMenu をダブルクリックすると、上のようなウィジット（２D画面）の編集ウィンドウが開きます。もしイベントグラフという文字が表示されていたら、右上の「デザイナー」のボタンを押すと上のような画面になります。

中央にあるウィンドウの中に、Reset, Resume, Quit のボタンを配置していきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/fab2dd9d-38cc-0603-62c6-c9a2524eb0ed.png)

左側にある「パレット」の中の「一般」の中にある Button の項目をクリックして、そのまま画面の中にドラッグして置きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/6fdbdaa9-97ac-2b3e-1dd3-2abd25fce1df.png)

ボタンのサイズや位置を適当に調整します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/d710aa9e-f9f9-d803-b42f-fa7e41b5ced9.png)

右にある「詳細」のところで、ボタンの名前を ResetButton に変更しておきます。これはボタンに表示されるテキストではなくて、ボタンをブループリントの中で参照するときに使う名前です。テキストは次の操作で追加します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/2cc3fbd5-7a7f-d23f-c4fb-4dc6907a4398.png)

再び左側の「一般」の中にある "Text" をマウスでクリックして、そのままドラッグしてさきほど配置したボタンの上にドロップします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/2e9259e7-af62-936f-df84-e2104866f1e5.png)

テキストをボタンのところまでもっていったときに、ボタンの周りに青い枠ができたときに、マウスのボタンを離します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/96deb48c-dba6-9a23-2d6c-20d2ad8ae9b2.png)

このようにすると、左側にある ResetButton の項目のすぐ下に、インデントされた形で「テキストブロック」という項目ができるはずです。テキストがこのように入れ子状態になっていれば、ボタンを動かしたときにテキストも一緒についてくるようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/154e692c-932e-82fe-85cb-9707a3702713.png)

同じ要領で、ResumeButton と QuitButton も作ります。左側の「階層」のところが、上の図のようになっていればOKです。

## Qキーを押したらメニューが表示されるようにする

今作ったメニューを、Qキーを押したときに表示するようにします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/d9a1e680-4a78-117a-0997-0880afeba81c.png)

Widget の編集画面は一度閉じて、メインの画面に戻ります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/f39b818b-a3a2-ed96-454f-3e5d8a7fb042.png" width="60%"/>

メインウィンドウの上にある「ブループリント」のメニューから「レベルブループリントを開く」を選びます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/43d96c22-2a47-77c8-7d55-80860a4a22e3.png)

こんな画面が開くはずです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/e935a954-a891-6046-0053-58026cc4f0ab.png)

上のようなグラフを書きます。

### メニューの初期化をする

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/ddfcbb14-58ff-7e66-8fb7-0fe8609956a3.png)

BeginPlay イベントは、右クリックして BeginPlay と入力すると出てきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/31f95be1-ea49-c3c2-add8-3458ad668ec4.png)

ウィジェットを作成のノードは、右クリックして CreateWi くらいまで入力すると出てきます。配置したあとに Class の項目で MainMenu を選ぶと、ノード名が 「Main Manu ウィジェットを作成」に変わります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/95400e25-baec-20c2-8421-e741f4128f47.png)

右にある「セット」は、Main Menu ウィジェットを作成の Return Value から線を出すと出てくるメニューから「変数へ昇格」を選ぶと作成できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/9caef57d-c94b-886a-3399-9cf851193172.png)

作成した直後は、変数名が NewValue_0 とかになっているので、MainMenu という名前に変更しておきます。これで、ゲームの開始時に MainManu にメニューのウィジェットが作られるようになりました。ただし、メニューは作られただけで画面には表示されていない状態になっています。

### キーを押したらメニューを表示する

下の図のようなグラフを書きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/b2cd7b3d-22b7-7d28-c8a1-2b1144ee5ea1.png)

このグラフで、Qキーを押したときにメニューを表示して、メニュー以外のところ（ゲーム画面）はマウスで操作できないようにして、最後にマウスカーソルを表示するという処理をしています。

### キーを押したときのイベントの取得

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/a4ed5877-0bf7-c3b9-460c-e79536964fc1.png)

左上のQと書かれた赤いノードは、右クリックして AnyKey と入力して出てくる「いずれかのキー」という項目を選ぶことで配置できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/fb1bc0f7-ad8d-1c7b-5dcf-80906b7dec62.png)

配置された直後はこのような状態になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/644b7841-398b-9448-efef-fa19689f14bd.png)

このノードを選択すると、右側の詳細のところに「入力」という項目が表示されるので、そこの Input Key のメニューを開いて、Q と入力します。すると上の図のように Q という文字が選べるので、それを選びます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/72f01765-7cd7-d653-72ff-1c78b91fde1e.png)

すると、このような表示になり、Qキーを押したり離したりしたときのイベントが拾えるようになります。

### ゲームが中断されていない状態かを判定する

Qキーが押されたとき、すでにゲームが中断していたら何もしないようにするために、下のようなグラフを追加しています。今回のプログラムでは、この処理を入れなくても正常に動作するはずですが、何らかの原因ですでにゲームが中断しているときにQキーのイベントを拾って、再度メニューを表示しようとしないように、念のため入れてます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/08118067-d498-c5ba-b579-beec2c67167d.png)

ブランチのノードは Branch と入力することで配置できます。

### メニューのボタン以外を操作できないようにする

ゲームが中断されているときに、表示されているメニュー以外のオブジェクト（メニューの背景に表示されている自分のキャラとか）がマウスでクリックできたりしてしまわないように操作をロックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/edca3968-4db8-d53b-f506-a1b2ce52f1f7.png)

SetInputModeUIOnly というノードで、メニュー以外は操作できないようにロックしています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/e77dc1d4-9913-a970-e7b7-2a2328340c9b.png)

MainMenu というノードは、画面左側にある「変数」の中にできている MeinMenu の項目をドラッグドロップして、Get MainMenu のメニューを選ぶことで配置できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/98ecef6c-3bfa-16e3-10cc-4705ed41363a.png)

Set Input Mode UI Only の In Mouse Lock Mode は Lock on Capture を選んでおきます。これを選ぶことで、メニューの配置されている範囲内だけマウスカーソルが動くようになります。

### メニューを画面に表示する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/2e30b111-c240-f79f-3690-768c5c042682.png)

Add To ViewPort というノードを使うことで、あらかじめ作っておいた MainManu を画面内に表示します。

### ゲームを一時停止してマウスカーソルを表示する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/8d8229d0-9e54-2766-2e00-387b1bb80fef.png)

SetGamePaused というノードで、ゲームを一時停止状態にしたり、再開したりできます。Paused にチェックを入れると一時停止状態になり、チェックをはずすと一時停止が解除されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/0285b435-5bab-f625-45e9-c7f44caf09c1.png)


「セット」のほうは、右クリックして SetShow と入力して、右上の「状況に合わせて表示」のチェックを外すと、SetShowMouseCursor という項目が選べるようになります。ターゲットには GetPlayerController の Return Value をつなぎます。Show Mouse Cursor にチェックを入れておくと、マウスカーソルが表示されるようになります。

## 実行

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/25c4fe96-a947-dff9-9133-ee8111a9ec35.png)

ここまで書けば、Qキーを押すとメニューが表示されるようになるはずです。メニューにあるボタンを押すこともできますが、押しても何も起こりません。以下、ボタンをおしたらそれぞれの機能が実行されるようにします。

# メニューボタンの機能を実装する

ここからはボタンを押したときの処理を書いていきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/24eab0a8-33b2-5a32-f093-11eff65da64d.png)

メニューのボタンに機能を実装するために、コンテンツブラウザの MeinMenu をダブルクリックして MainMenu のエディタを開きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/0cf3c42e-5f6f-74b8-a87e-f0e2e2fd55ae.png)

エディタが開いたら、右上にある「グラフ」というタブを押します。

## Quit ボタンを押したらゲームを終了する

まず、Quit ボタンを押したらゲームを終了するようにします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/dc0fff67-eedb-d31e-dff4-978f8a1bacf2.png)

このようにグラフを書くことで実現できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/e5f8be26-0f74-94e6-d5bf-802b8e2a1c0d.png)

OnCliked (Quit Button) というノードは、左側にある「変数」の中にある QuitButton を選ぶと、下のほうに「イベント」という項目が表示されます。その中に OnClick という項目があるので、その横の緑色に白地で＋と書かれたボタンを押すことで配置できます。

## Reset ボタンを押したらゲームを最初の状態からやりなおす

レベルを再度読み込むことで、ゲームを開始時の状態に戻します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/bfdadbd7-c518-c5a7-80b5-e47ba26217b1.png)

ゲームの中で使っているパラメータもすべてリセットされてしまうので、得点やHPを保存してやり直したいみたいな場合は、GameInstance を使うなどの工夫が必要です（多分）。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/54d9ff6b-7a35-e510-3f68-e3695b2ca38b.png)

OnCliked (Resume Button) は、Quit Button の時と同様にして、イベントの中の＋を押して配置します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/9e06cf95-0cd6-3b9a-efa9-e76c3a0bb5ee.png)

OpenLevel のノードで、レベルを開きなおします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/0c5542aa-505e-a3b1-9872-ed53ecb6272d.png)

Level Name に入れる文字列は、コンテンツブラウザで「コンテンツ」「ThirdPersonBP」「Maps」と辿ると見つけることができます（ThirdPerson プロジェクトの場合）。ここでは ThirdPersonExampleMap と入れています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/dbde9c2f-5f2b-e6ea-98cc-a809385726f1.png)

最後に、SetInputModeGameOnly ノードでゲーム画面でもマウスのイベントを拾うように戻しています。このノードを置かないと、メニューが消えてしまった後は何も操作ができなくなります（Qキーを押したときの処理で、メニュー上でしかマウス操作ができないように設定しているため）。

## Resume ボタンを押したらゲームを再開する

Qキーを押したときの、ほぼ反対の処理をすることで、ゲームに戻れるようにできます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/0741fa52-2bbb-dfcd-ab3e-0f5c377856b3.png)

設置しているノードは、Qキーを押したときの処理とほぼ同じです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/5441f4ab-1cbc-cbae-ae99-33131e01f1d9.png)

このノードで、画面からメニューを非表示にしています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/cb381a65-4b70-443c-bbc7-716692270725.png)

SetGamePaused ノードはチェックを外すことで、一時停止状態から復帰させることができます。また SetSHowMouseCursor ノードでは、チェックをつけないことで、マウスを非表示にできます。

## 実行

ここまでの処理で、すべての機能が実現できているはずです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/321eba78-8e7e-07ee-dc7b-1de83823c9eb.png)

静止画だと全然わかんないけど…