[UE4] ラーニングコースのブロックベースのゲームにセーブ機能を追加する

# はじめに
UnrealEngineのラーニングコースの[ブロックベースのゲームの構築](https://www.unrealengine.com/ja/onlinelearning-courses/building-a-block-based-game)で作成したゲームに、セーブ機能を追加してみました。
セーブ機能は[ブループリント ランタイムの保存とロード](https://www.unrealengine.com/onlinelearning-courses/blueprint-runtime-saving-and-loading)の内容を参考に作成しました。
<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/UE4Study?src=hash&amp;ref_src=twsrc%5Etfw">#UE4Study</a> <a href="https://t.co/oGymwRnmS1">pic.twitter.com/oGymwRnmS1</a></p>&mdash; 高浜 (@SatoshiTakahama) <a href="https://twitter.com/SatoshiTakahama/status/1477572560225464321?ref_src=twsrc%5Etfw">January 2, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
# 環境
Windows10
UnrealEngine 4.27.2

# 作り方
・UnrealEngineのラーニングコースの[ブロックベースのゲームの構築](https://www.unrealengine.com/ja/onlinelearning-courses/building-a-block-based-game)を一通り実施します。
・セーブする内容を定義する構造体S_SaveItemsを作成します。
構造体は、コンテンツブラウザ上で右クリック=>ブループリント=>構造体を選択して作成します。
変数は以下のようにClassとTransformを追加します。ClassにはBP BaseBlockクラスを型として、TransformはTransformを型として指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215278/be1ed4cc-1539-7130-2cc3-86a4c2edd513.png)
・SaveGameオブジェクトのSG_SpawnedBlocksを作成します。
SaveGameオブジェクトは、コンテンツブラウザ上で右クリック=>ブループリントクラスを選択し、親クラスにSaveGameを指定して作成します。
変数は以下のようにSpawnedBlocksとSlotNameを追加します。SpawnedBlocksには先ほど作成した構造体S_SaveItemsの配列を型として、SlotNameにはStringを型として指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215278/ba8af03d-01bb-431b-d800-e8193d8692fc.png)
・セーブ機能のインターフェースとしてBPI_SpawnBlocksを作成します。
インターフェースは、コンテンツブラウザ上で右クリック=>ブループリント=>ブループリントインターフェースを選択して作成します。
関数SpawnBlock, RemoveBlock, SaveBlocks, LoadBlocks, ClearBlocksを追加します。SpawnBlockとRemoveBlockは以下のようにインプットを指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215278/b32aad64-ee7f-221b-834f-563d78aa1260.png)
・ゲームモードGM_BlockGameを修正し、セーブ機能を追加します。
クラス設定から実装インターフェースにBPI_SpawnBlocksを追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215278/043648da-c982-9b60-3d75-fd5db4b4b1de.png)
変数CreatedBlocksList, SaveBlocksListを追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215278/f7f4c3d3-6429-f2d6-f09e-75cd8d50578b.png)
以下のようにイベントグラフにSpawnBlockの実装を追加します。
CreatedBlocksListにSpawnしたブロックを追加しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215278/feac37a4-4533-8817-4343-73ffcb016bac.png)
以下のようにイベントグラフにRemoveBlockの実装を追加します。
CreatedBlocksListからブロックを削除しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215278/0dbf1c0a-0907-f401-b15a-4b3a75f37922.png)
以下のようにイベントグラフにSaveBlocksの実装を追加します。
CreatedBlocksListに保存されたブロックをSaveGameオブジェクトを使用してセーブしています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215278/9093797a-af85-507c-935e-1cf1e082afe9.png)
以下のようにイベントグラフにLoadBlocksの実装を追加します。
SaveGameオブジェクトからロードしたブロックをCreatedBlocksListに追加し、Spawnします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215278/2697e4c8-3cdd-aeb4-c23d-d79caef2058d.png)
LoadBlocksの前半拡大
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215278/1256f560-c56b-405a-e98d-e20dc4f071a4.png)
LoadBlocksの後半拡大
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215278/8bd54333-3dc1-f276-e2b7-6fd460158d05.png)
以下のようにイベントグラフにClearBlocksの実装を追加します。
セーブされていた内容を削除しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215278/571428f7-81d2-331d-34a3-006cb2f6ca72.png)
以下のようにイベントグラフに起動時にLoadBlocksを実行する処理を追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215278/431b9c71-6656-5491-11a5-a8d9cbe258c5.png)

・BP_BlockPlayerを修正し、セーブ機能を使うように修正します。
BP_BlockPlayerのイベントグラフでブロックをSpawnしている箇所(インプットアクションPlaceBlockから始まる処理)に追加します(以下赤枠の箇所)。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215278/3fae318a-6619-09cd-e36e-68557fc85f52.png)
追加箇所拡大
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215278/20fc7c88-dc1f-9018-de79-818704606d06.png)
イベントグラフでブロックを削除している箇所(インプットアクションRemoveBlockから始まる処理)に追加します(以下赤枠の箇所)。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215278/587f182c-0c23-c488-d5f4-9fd1bff9591f.png)
追加箇所拡大
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215278/5830d74b-c886-fbc4-a5f3-d9be4df5a37c.png)
イベントグラフにキー入力を追加します。
キー7を押したときにセーブを実行、キー8を押したときにセーブデータをクリアします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215278/5c377929-73d6-5aa2-ec44-c919fdb66b71.png)

# 参考資料
・[ゲームを保存して読み込む](https://docs.unrealengine.com/4.27/ja/InteractiveExperiences/SaveGame/)
SaveGameオブジェクトの公式ドキュメントです。