47.SaveGameとは? データをセーブ,ロードしてみよう
データをセーブ,ロードするSaveGameクラスとは?
UnrealEngineでデータを保存する一般的な方法として「SaveGame」というブループリントクラスを使用します。SaveGameはゲームのデータを保存,ロード,削除など行うためのブループリントクラスになります。
https://scrapbox.io/files/65c5e40c82b83500244172d9.png
SaveGameを使用すると例えば、獲得したコインの枚数とかスコアとかレベルやスキルとかゲームの進行状況とか、そういったデータを保存したりロードしたりする事ができます。
①プレイヤーのレベルのデータを保存,ロードしてみよう|実践
今回実装する機能です↓
https://youtu.be/lqxS6Po6Q2Y
Lキーをおしたらレベルが+1されて保存されます。次のゲーム開始時に保存されたレベルデータをロードして「LEVEL4」のように表示する機能です。データを削除する機能も実装していきます。
①データを保存する|実践
今回はサードパーソンのプロジェクトを使用します。
まずはBlueprintsフォルダを作成して右クリック > ブループリントクラス > savegameと検索してSaveGameクラスを選択します。作成したら名前をBP_SaveGameにします。
https://scrapbox.io/files/65c5e4eb952d660024a9e08d.jpg
BP_SaveGameを開いて、保存するための変数をInteger型でSaveGame_PlayerLevelという名前で作成します。
https://scrapbox.io/files/65c5e542ad0f7e00244eed61.png
コンパイルします。
そしたら今度はレベルブループリントを開きます。
https://scrapbox.io/files/65c5e56a0d8bc500249ae5ec.jpg
レベルブループリントに以下のようにノードを作成します。BeginPlayからCreateSaveGameObejectノード作成し、BP_SaveGameをセットします。
https://scrapbox.io/files/65c5e5b294f1fc0026d8b9b1.png
CreateSaveGameObejectノードとは?
まずデータを保存する前にSaveGameObjectを生成する必要があります。生成したSaveGameをSaveGameObjectと言いますが、SaveGameObject = SaveGameというブループリントクラスという認識でオッケーです。
CreateSaveGameObejectノードのReturnValueを右クリックで 変数を昇格、その後変数の名前を「BP_SaveGame」にします。
https://scrapbox.io/files/65c5e6990d8bc500249af578.png
BP_SaveGameからSaveGametoSlotを作成します。SlotNameには「SaveData」と入力します。最後にPrintStringで「SaveGameを生成、保存しました。」と表示します。
https://scrapbox.io/files/65c5e6e0f7a345002c2c11fc.png
Save Game to SlotのSave Game ObjectにはBP_Save Gameを入れます。
https://scrapbox.io/files/65c5ebd1e266a400244fdfbc.jpg
SaveGametoSlotとは?
SlotNameで入力した名前のスロットにSaveGameObjectを保存するノードです。簡単に言うとセーブするノードです。変数SaveGame_PlayerLevelを内包しているBP_SaveGameを丸ごと保存するというイメージです。
最初に保存する理由は?
生成したSaveGameObjectは一旦保存するとゲームを終了しても消える事はありません。なのでSaveGameObjectを生成したタイミングで一旦保存しておくと次回からSaveGameObjectを再度生成する必要が無くなります。最初に必ず保存しなければならないという訳ではありませんが、SaveGameObjectを生成したら一旦保存すると覚えておいてもよいと思います。
🐱つまりここまでの流れとしてはSaveGameObjectを生成→SaveGameObejectを保存(SaveGameに作られた変数を保存)といった感じになります。
一旦プレイしてみましょう。
https://scrapbox.io/files/65c5ec7b05045b0024bb9517.gif
これでSaveGameObjectが生成されて、保存されました。
なおSaveGameObjectは生成されるといってもレベル上に生成されるという概念ではありません。ワールドアウトライナーを確認してもSaveGameObjectは無いので注意です。
ゲームはそのまま終了します。
これでデータが保存されたのですが、保存したデータの位置を確認しておきましょう。保存されたデータはエクスプローラーでいうと、プロジェクト名 > Saved > SaveGamesフォルダ内にあります↓SaveGametoSlotノードで保存名はSaveDataという名前にしておいたので、SaveData.savというファイルがある事が確認できます。
https://scrapbox.io/files/65c5ed12d195200024d392d7.png
ちなみに.savファイルはゲームのデータの事で、ゲーム上でしか開く事ができません。
一旦ここまでを解説
https://scrapbox.io/files/65c5edb8fba542002422db2a.png
ここまでを簡単に解説するとSaveGametoSlotノードで、SaveGameというブループリントクラスをSaveDataという名前で保存した形になります。このSaveDataの中に作成したBP_SaveGameが保存されているというイメージです。
SaveGameObjectは一旦保存するとゲームを終了しても無くなりません。なので次回のプレイからは再度SaveGameObjectを生成する必要が無くなります。そこでSaveGameObjectが存在するかどうかのブランチ処理を作っていきます。
Beginplayの後にノードを追加していきます。
https://scrapbox.io/files/65c5ee7fb2fc69002427bc9c.png
DoesSaveGameExistノードを作成して、SlotNameにSaveDataと入力します。ブランチノードを作成してFalseから既存のノードに接続します。
https://scrapbox.io/files/65c5eedde530ab0023e470ae.png
DoesSaveGameExistノードとは?
DoesSaveGameExistノードはSlotNameに入力した名前のSaveGameが存在するか確認するノードです。存在すればture、存在しなければfalseを出力します。
https://scrapbox.io/files/65c5ed12d195200024d392d7.png
例えば今回はSlotNameにはSaveDataと入力して、SaveGamesフォルダには現在SaveDataがある状態なのでこの状態だと存在しているという事でtrueになります。
true側にPrintStringを作成しておきます。「SaveGameは存在するのでロードします」と入力します。後からロードする処理は作成していきます。
https://scrapbox.io/files/65c5efba0b254300260f4f8b.png
一旦プレイしてみましょう。
https://scrapbox.io/files/65c5f1b005045b0024bbd1d6.gif
ここまでのノード解説
https://scrapbox.io/files/65c5f1ccc68f930025371b22.png
前回プレイしたタイミングでSaveGameは生成、保存されています。一度保存されるとゲームが終了してもSaveGameは存在し続けるため、今のプレイではDoesSaveGameExistノードでSaveDataというSaveGameが存在する事が確認されて「SaveGameは存在するのでロードします」とテキスト表示された形になります。
🐱ではSaveGame_PlayerLevelの変数(Integer型の初期値0)を保存したので、ロードして0という値を取得してみましょう。
②保存したデータをロードする|実践
では今度は保存データをロードする処理を作っていきたいと思います。
保存したデータをセットするために、レベルブループリント側にPlayerLevelという変数を作成します。
https://scrapbox.io/files/65c5f25c71096a00257ac269.png
レベルブループリントのブランチのtrue側から以下のノードを作っていきます。LoadGamefromSlotを作成してSlotNameにはSaveDataと入力します。CastToBP_SaveGameで参照を作ります。
https://scrapbox.io/files/65c5f4a77a7b380026326dbc.png
一旦続けて作ってしまいましょう。
続けてGetSaveGamePlayerLevelで取得して、PlayerLevelにセットします。それをPrintStringで表示させます。Appendで「LEVEL」というテキストを結合させます。
https://scrapbox.io/files/65c5f50c59806e0026b8bf70.png
LoadGamefromSlotノードとは?
LoadGamefromSlotはSlotNameの名前(SaveData)のデータをロードします。つまり先ほどエクスプローラーで確認したこのデータ↓をロードします。
https://scrapbox.io/files/65c5ed12d195200024d392d7.png
このSaveDataにはSaveGame_PlayerLevelという変数が内包されており、ロードする事でその変数を取得する事ができるようになります。
作ったノード全体解説
https://scrapbox.io/files/65c5f65ce78f2500255fe08c.png
まずLoadGamefromSlotでSaveDataという名前でSaveGameをロードします。そのSaveGameからCastToノードで参照を作成して、BP_SaveGame変数にセットします。BP_SavaGameで作成してあるSaveGame_PlayerLevelを取得します。それを一旦レベルブループリント側のPlayerLevelにセットしてテキスト表示しています。
これでプレイしてみましょう。
https://scrapbox.io/files/65c5f6a689f7470024929b96.gif
SaveGameは既に存在しているのでデータのロードが行われて、データの内容「0」と組み合わせて「LEVEL0」とテキスト表示されます。
😺これでセーブとロードの機能が実装できました。では次にゲーム中にセーブするデータ内容を変更して、ロードしてみてみましょう。
③データを変更して(レベルを上げて)保存する
ではここからは試しに保存するデータ内容を変更してみましょう。Lキーを押したらPlayerLevelを+1していってデータを保存してみます。
レベルブループリントに以下を追加していきます。Lキーを押したらPlayerLevelに+1してテキスト表示させます。
https://scrapbox.io/files/65c5f739d93c500025fb69c8.png
そしたらBP_SaveGameに変更したPlayerLevelをセットします。その後SaveGametoSlotで保存します。SlotNameはSaveDataと入力します。
https://scrapbox.io/files/65c5f75257a1ba00259f205c.png
ノード解説
これでLキーを一回押した時にPlayerLevelは「1」になります。その「1」がSaveGameObjectの変数SaveGame_PlayerLevelに渡されます。そしてその変数を持っているSaveGameが保存されます。
一度プレイしてLキーを何回か押して、ゲームを終了します。
https://scrapbox.io/files/65c5f7bd5cb2d700253e96d3.gif
例えばLキーを6回押したら「6」というデータが保存された形になります。
再度プレイしてみましょう。
https://scrapbox.io/files/65c5f7ddc1dbe90025122e15.gif
一旦ゲームを終了して再度スタートすると「6」がロードされて「LEVEL」というテキストと結合されて「LEVEL6」と表示されます。
😺こんな感じにゲーム中に変更したデータ、例えばスコアとか獲得したコインの枚数とかそういったものを保存したりロードしたりする事ができます。最後にセーブデータを削除する方法について紹介します。
④セーブデータを削除する|実践
😺ではセーブデータを削除する(リセットする)にはどうすれば良いのでしょうか?これはシンプルでDeleteGameinSlotノードを使用するだけです。
https://scrapbox.io/files/65c5f8813e67d9002407b60a.png
DeleteGameinSlotノードとは?
DeleteGameinSlotはSlotNameに記載されたセーブデータを削除するノードです。なので実行するとSaveGame_PlayerLevelの変数は初期値の0になります。SaveGameObjectもこれで存在しなくなります。
プレイしてDeleteキーを押して終了します。
https://scrapbox.io/files/65c5f8b788c28500246319df.gif
データが無くなったのかエクスプローラーでも確認してみましょう。先ほどと同じSaveGameフォルダを開くとデータが無くなっているのが確認できます。
https://scrapbox.io/files/65c67e014b7e6c00254f6de6.png
再度プレイしてみましょう。SaveGameObjectは存在しないので新規作成されるのが確認できます。
https://scrapbox.io/files/65c5ec7b05045b0024bb9517.gif
データをセーブ,ロードするのに使用するノード一覧
まず今回使用したノードです↓
table:今回使用したノード
CreateSaveGameObject SaveGameを生成するためのノードです。保存する前に生成する必要があります。
DoesSaveGameExist SaveGameが存在するか確認するノードです。存在するならtrue,存在しないならfalseを出力します。
SaveGametoSlot SlotNameに入力した名前でSaveGameを保存します。要するにデータをセーブするノードです。
LoadGameformSlot SlotNameに入力した名前でSaveGameをロードします。要するにデータをロードするノードです。
DeleteGameinSlot SlotNameに記載されたセーブデータを削除するノードです。
table:今回使用しなかったノード
AsyncSaveGametoSlot SlotNameに入力した名前でSaveGameを保存します。要するにデータをセーブするノードです。
SaveGametoSlotノードと違い、セーブの終了を待たずに後続のピンから実行します。
Completedでロードが終了したタイミングをとる事ができます。
AsyncLoadGameformSlot SlotNameに入力した名前でSaveGameをロードします。要するにデータをロードするノードです。
LoadGameformSlotノードと違い、ロードの終了を待たずに後続のピンから実行します。
Completedでロードが終了したタイミングをとる事ができます。
Asyncがあるとないのノードの違いは?
まずAsyncですが、日本語だと非同期の事です。非同期とは処理を待たずに次の処理を進める事です。
https://scrapbox.io/files/65c67f8831519b0025c6bbce.png
AsyncSaveGametoSlotとSaveGametoSlotの違いですが、SaveGametoSlotノードだとセーブが終了するまで次のノードは実行しません。一方AsyncSaveGametoSlotはセーブの終了を待たずに次のノードを実行します。どちらを使えば良いのかというと、どちらでも良いです。例えばセーブし始めた時に、チュートリアルのテキストを表示するノードを表示したい時などはAsyncSaveGametoSlotノードを使用するといった感じでよいと思います。ただ、今回実装したようなデータの量などであればセーブは一瞬なので最初はSaveGametoSlotを基本使っていけば良いと思います。