AG12.データのセーブ機能を実装する
🐱現時点のアクションゲームではコインは拾ってもレベルが切り替わったり、プレイを終了した時点で0にカウントがリセットされてしまいます。なのでステージが切り替わった後や再度プレイした後にも拾ったコイン枚数が引き継がれるようにデータのセーブ機能を実装していきます。
今回実装する機能
今回のページでは拾ったコイン枚数をセーブして、再度プレイした時とステージが切り替わった時にコイン枚数をロードして画面のUIにコイン枚数を反映させるという事を行っていきます。
https://youtu.be/--1IntU1uso
🐱では作る前に少し複雑なのでセーブ機能を実装する流れを先に解説しておきます↓
セーブ,ロードを実装する流れを先に確認しておこう!
まずセーブ,ロードを実装するにはSaveGameというブループリントクラスを使用して実装していきます。以下実装する大体の流れです↓
https://scrapbox.io/files/65d498dafa31a700253e8884.jpg
🐱といった感じにセーブ,ロード機能を実装していきます。では作っていきましょう!
①まずはセーブに必要なSaveGameを生成して保存する
まずはセーブするために必要なSaveGameのブループリントクラスを用意していきます。
先にLEVEL1のステージを開いた状態にしておきます。
https://scrapbox.io/files/65d49af060e9b5002413d383.png
Blueprintsフォルダで右クリック > ブループリントクラス > SaveGameと検索してSaveGameを選択 > 選択をクリックします。
https://scrapbox.io/files/65d49b1e738fa90024ccba29.jpg
作成したブループリントクラスをBP_Jumper_SaveGameという名前にします。
https://scrapbox.io/files/65d49b2c4176030024089e72.jpg
BP_Jumper_SaveGameを開いてSaveGame_PlayerCoinというInteger型の変数を作成します。
https://scrapbox.io/files/65d49b380c6cbd0024cb3473.png
コンパイルしておきます。
🐱このSaveGame_PlayerCoinがセーブする整数データになります。ではSaveGameを生成,保存していきます。そして今回セーブ,ロードを実装する場所はゲームモードです。ゲームモードであれば適用した全てのレベルで実行されますし、セーブの機能なので直感的にもゲームモードに実装するのが良いかと判断しました。
今度はBP_Jumper_GameModeのイベントグラフを開きます。
https://scrapbox.io/files/65d49b54ccaabd00247a7a06.png
🐱まず一番最初にコイン枚数を後から変更するために、ゲームモードでコイン枚数のUIを作ったWBP_Playerを取得していきます。
BP_Jumper_GameModeに既に作成してあるノードは今回は変更しないので無視して、カスタムイベントを作成します。名前は「CreateSaveGame_OR_LoadSaveGame」とします。
https://scrapbox.io/files/65d49c07a0396c002576a5bf.jpg
続けてDoesSaveGameExistノードを作成してSlotNameにSaveDataとします。ブランチノードを作成して実行ピンとReturnValue両方繋げます。
https://scrapbox.io/files/65d49c2b3289f800250d843f.jpg
DoesSaveGameExistノードとは?
DoesSaveGameExistノードはSaveGameが存在するか確かめるためのノードです。存在する場合はtrue,存在しない場合はfalseが出力されます。
🐱ではセーブするためにまずSaveGameを生成していきます。
False側からCreateSaveGameObjectノードを作成してSaveGameClassにBP_Jumper_SaveGameをセットします。その後RetrunValueを右クリック > 変数へ昇格 > 作成された変数の名前をBP_Jumper_SaveGameとします。
https://scrapbox.io/files/65d49c657f91650026a1688e.png
CreateSaveGameObjectノードとは?
CreateSaveGameObjectはSaveGameを生成するためのノードです。今回BP_Jumper_SaveGameを選択したのでそれを生成した形になります。
SaveGametoSlotを作成してSaveGameobjectにBP_Jumper_SaveGameをセットします。SlotNameに「SaveData」と入力します。最後にPrintStringで「SaveGameを生成,保存しました」と入力します。
https://scrapbox.io/files/65d49cb4b9e437002497b6b7.jpg
SaveGametoSlotノードとは?
SaveGametoSlotはSaveGameをセーブするためのノードです。要するにSaveGametoSlotノードを使用するとSaveGameに作成した変数をデータとして保存する事ができます。つまりセーブするためのノードになります。
🐱そしたらこの作成したカスタムイベント「CreateSaveGame_OR_LoadSaveGame」を実行する必要があります。BP_Playerから呼び出して実行させます。
BP_Playerを開きます。
https://scrapbox.io/files/65d49cce471f62002693da8f.jpg
BeginPlayから繋がるノードの最後に追加していきます。
https://scrapbox.io/files/65d49cf6c754900024e7da7e.jpg
手前のCastToBP_Jumper_GameModeのAs~ピンから伸ばして、「CreateSaveGame_OR_LoadSaveGame」のカスタムイベントを呼び出します。
https://scrapbox.io/files/65d49d036b036c00255a165a.jpg
ここまでの内容解説
BP_PlayerからBP_Jumper_GameModeの「CreateSaveGame_OR_LoadSaveGame」を呼び出して実行します。
BP_Jumper_GameModeのカスタムイベントが実行されると、最初にDoesSaveGameExistノードでSaveGameのデータが既に存在するかどうかチェックします。もし存在しない場合SaveGameを生成して、「SaveData」という名前でSaveGame自体を保存します。
🐱要するにゲーム開始時に一度SaveGame自体を生成して保存しているという事になります。
最初にセーブする意味とは?
ゲーム開始時にセーブする必要は無いように思えますが、今回のようにSaveGameを生成したら一旦SaveGametoSlotノードで保存しましょう。保存しておくと今後のゲームプレイでずっとSaveGameは存在し続けるようになります。保存しないままゲームを終了すると次のプレイでも再度SaveGameを生成する必要があります。正直どっちでも良いのですが、SaveGameを生成したら一旦保存しておくと覚えておけばオッケーです。
一旦これでプレイしてみましょう。最初のプレイだけ「SaveGameを生成,保存しました」と表示されます。
https://scrapbox.io/files/65d49d710bb2950025968c1d.png
このテキストは一回目しか表示されません。確認できなくてもご安心ください。後からセーブデータを削除する機能を実装するのでそれで削除した後に、再度テキストが表示される状態になって確認できます。
ここまでBP_Jumper_GameModeに実装した全ノードです↓
折り畳みグラフがあるノードをコピペする場合は上のリンク先にアクセスして、CodetoCopyからコピーする必要があります。また変数は手動で作成する必要があります。
🐱これでSaveGameを生成して一旦保存する事ができました。保存したデータファイルがエクスプローラーで確認できるので確認してみましょう。
コンテンツブラウザのコンテンツを右クリック > エクスプローラーで表示するを選択します。https://scrapbox.io/files/65d49db0fb787e0025e69276.jpg
エクスプローラーが開きます↓
https://scrapbox.io/files/65d4a1182bae22002511955d.jpg
保存したプロジェクトがある場所、Jumper > Saved > SaveGamesフォルダを確認してみましょう。SaveData.svというデータが保存されているのが確認できます↓
https://scrapbox.io/files/65d4a126dc6c94002e7a3244.png
データが無かった場合は再度ノードを見直してプレイしてみてください。
この~.savデータについて
SaveGameToSlotノードによって~.savという名前でデータが保存されます。この~.svフォルダはゲーム内でしか開く事ができないのでダブルクリックしても中身のデータは確認できません。
🐱SaveGameを一旦生成,保存した事によって、いつでもセーブとロードが可能な状態になりました。次にテストプレイ用のセーブデータを削除する機能を追加しておきましょう。
②テスト用にセーブデータをリセットする機能を付ける
テスト用にセーブデータをリセットする機能を付けていきます。
LEVEL1のレベルブループリントを開きます。
https://scrapbox.io/files/65d4a17e76c42100253c2ffc.png
DeleteキーからDeleteGameinSlotを作成してSlotNameをSaveDataと入力します。PrintStringで「セーブデータを削除しました」と入力します。
https://scrapbox.io/files/65d4a194f5450d00257e8202.png
DeleteGameinSlotとは?
DeleteGameinSlotノードでセーブデータを削除できます。エクスプローラーで確認したSaveDataもこれで消えて、SaveGameもこれで存在しなくなります。
プレイしてDeleteキーをおしてゲームを終了します。
https://scrapbox.io/files/65d4a1bc2143e30025657cac.png
再度エクスプローラーでデータが無くなっているか確認しましょう。
もう一度プレイしてみるとSaveGame(セーブデータ)はもう存在しないのでSaveGameが生成,保存されてコイン枚数は0にリセットされます。
https://scrapbox.io/files/65d4a1c9c754900024e7f836.png
🐱この機能はセーブデータをリセットして再度1から試したい時にご使用ください。次に保存したデータをロードする処理を作っていきます。
③保存したデータをロードしてセットする
では今度はセーブしたデータをロードする処理を作ります。
BP_Jumper_GameModeを開いてLoadedPlayerCoinという名前でInteger型を作成します。
https://scrapbox.io/files/65d4a1efdc6c94002e7a3712.jpg
作っていたBP_Jumper_GameModeのブランチのTrue側からノードを作っていきます。
https://scrapbox.io/files/65d4a201c115700025017fc7.jpg
BP_Jumper_GameModeのTrue側からPrintStringで「SaveGameは存在するのでデータをロードします」と入力、LoadGamefromSlotでSlotNameを「SaveData」と入力します。
https://scrapbox.io/files/65d4a2092bae2200251199bd.jpg
LoadGamefromSlotとは?
LoadGamefromSlotノードは、SlotNameで保存されたSaveGameをロードするためのノードです。つまり保存されたデータを読み込むノードです。
LoadGamefromSlotからCastToBP_Jumper_SaveGameを作って、セットします。そこからSaveGame_PlayerCoinをGetで取得してLoadedPlayerCoinにセットします。
https://scrapbox.io/files/65d4a238d6e62c002573c7e6.png
続けてPrintStringでLoadedPlayerCoinを表示します。その後CastToBP_Playerノードを作成します。
https://scrapbox.io/files/65d4a245ec6ed800247ab304.png
ノード解説
これでロードしたコイン枚数をPrintStringで一旦表示しています。確認用のためです。
続けてLoadedCoinをBP_PlayerのMyCoinへセットします。既存の変数WBP_PlayerをGetで追加して、既に実装してあるカスタムイベント「SetCoinTextを」呼びます。
https://scrapbox.io/files/65d4a25fccaabd00247ab1d3.png
ノード解説
これでセーブしたコイン枚数をロードして、ロードしたコイン枚数を一度LoadedCoinに入れます。その後、BP_PlayerのMyCoinにセットして最後にSetCoinTextでコイン枚数をUIで表示しています。
プレイしてみましょう。「SaveGameは存在するのでデータをロードします」の後に「0」と表示されます。また元々「00」のテキストなので変化はありませんが、UIのテキストも0がロードされてテキストに反映されています。
https://scrapbox.io/files/65d4a2b0db1c0a00241a8353.png
ここまでのノード解説
https://scrapbox.io/files/65d4a2e4cfe07e0026594213.png
コイン枚数を保存するSaveGame_PlayerCoinをSaveGameに作成しました。そのSaveGameを保存したデータがエクスプローラーで確認したSaveData.svにあたります。そのセーブデータをLoadGamefromSlotでロードして、ロードしたSaveGameからSaveGame_PlayerCoinの整数データを取り出してそれをテキスト表示した形になります。なのでSaveGame_PlayerCoinの初期データは「0」なのでそのデータが保存されて、次プレイ時にロードされて「0」と表示された形になります。
BP_Jumper_GameModeが長くなったのでまとめておきます。False側のノードを全てを折りたたんで、CollapseGraph_CreateAndSaveとします。True側のノードも同じく折りたたんでCollapseGraph_Loadとします。
https://scrapbox.io/files/65d4a3048d16d200259d6653.png
🐱では、ゲーム開始時にコイン枚数のロードまでは実装できたので次に拾ったコイン枚数をゴール時に保存する処理を作っていきます。
④ゴールした時に拾ったコイン枚数を保存する
同じくBP_Jumper_GameModeに以下を追加していきます。カスタムイベント作って名前をSaveCoinとします。詳細からインプットのプラスボタンを押して、Integer型のCurrentPlayerCoinという名前のインプットを作成します。
https://scrapbox.io/files/65d4a36f417603002408df72.png
BP_Jumper_SaveGameの変数をGetで追加してそこからSaveGame_PlayerCoinを追加します。最後にSaveGametoSlotでSaveDataと入力します。
https://scrapbox.io/files/65d4a37eb294f700258f7d75.png
ノード解説
まず拾ったコインをBP_Jumper_SaveGameに実装したSaveGame_playerCoinにセットします。そのセットしたBP_Jumper_SaveGameをSaveGametoSlotでセーブしています。つまりこのSaveCoinのカスタムイベントを実行するとコイン枚数をセーブするという事になります。
ちなみに...
ちなみにReroute(ピン留め)ノードを作成した時にノードと水平にならない時があります。そんな時には二つのノードを選択した状態でQキーで水平上に整列させる事ができます。
https://scrapbox.io/files/65d4a38871b19a0024891345.gif
SaveCoinのカスタムイベントより後続のノードを選択 > 右クリック > ノードを折りたたむを選択して名前を「CollapseGraph_SaveCoin」にしておきます。
https://scrapbox.io/files/65d4a3af7f91650026a19a5e.png
わかりやすく以下のblueprintUEのようにコメントをつけておきます。
🐱次にゴールした時に今作ったSaveCoinのノードを呼び出します。ゴールを検知するノードを実装しているBP_GoalPointを編集していきます。
BP_GoalPointを開きます。
https://scrapbox.io/files/65d4a3ecdd041f002cddaea2.png
長すぎるのでまとめておきます。CastToBP_Player以降のノードを折りたたみます。CollapseGraph_Goalという名前にします。
https://scrapbox.io/files/65d4a4504dd90c00243ca12e.png
CollapseGraph_Goalから後続にノードを作っていきたいので、 CollapseGraph_Goalを開いて一番最後のノード、DisabeleMovementからアウトプットに実行ピンをドラッグして繋げます。
https://scrapbox.io/files/65d4a465bd59a70025ca95df.gif
イベントグラフに戻ってCollapseGraph_Goalに実行ピンがあるのが確認できます。
https://scrapbox.io/files/65d4a47d63f2e300262defec.png
CollapseGraph_Goalから以下のように作成します。CastToBP_Jumper_GameModeとGetGameModeを作成します。SaveCoinを呼んでBP_PlayerからMyCoinをGetで繋げます。
https://scrapbox.io/files/65d4a4882c1af90024eb3cb7.png
ノード解説
BP_GoalPointとプレイヤーが触れた瞬間に作ったノードは起動してSaveCoinのカスタムイベントを起動しています。
こちらのノードもまとめておきます。
https://scrapbox.io/files/65d4a4c9246088002d409456.gif
入力ピンと実行ピンが逆になった場合
以下のように入力ピンと実行ピンが逆になる場合があるので対処法を紹介しておきます。
https://scrapbox.io/files/65d4a51d854ce10026c2684f.jpg
CollapseGraph_SaveCoinを開いて、インプットを選択した状態で詳細からselfと書かれた項目を下にドラッグします。そうすると実行ピンが上になって元に戻ります。
https://scrapbox.io/files/65d4a56aa72ecd0026a98cd2.gif
名前はCollapseGraph_SaveCoinとしておきます。
https://scrapbox.io/files/65d4a5778d16d200259d7a53.jpg
イベントグラフに戻るとこんな感じになりました↓
https://scrapbox.io/files/65d4a58960e9b50024141dbb.png
テスト用に二枚のコインをゴール前に配置して「現在のカメラ位置」を選択し、ゴール前からプレイしてみましょう。
https://scrapbox.io/files/65d4a5a660668000256332f9.png
コインを拾ってゴールして、NEXTボタンを押してみましょう。
https://scrapbox.io/files/65d4a5c5a6f63200246067eb.gif
「SaveGameは存在するのでデータをロードする」の後に拾った拾ったコインの枚数「2」と表示されるようになりました。UIのテキストもコイン枚数が02になっている事が確認できます。
https://scrapbox.io/files/65d4a5d0b2036d0024da5096.png
一旦ゲームを終了して再度プレイしてみましょう。コイン枚数のロードはゲーム開始時に実行されるので拾ってセーブしたコインの合計枚数が表示されます。
https://scrapbox.io/files/65d4a5fc2c1af90024eb5344.jpg
ノード解説
LEVEL1にてコインを拾った枚数「2」という整数データを保存しました。セーブ,ロードする機能はゲームモードに作り、LEVEL1とLEVEL2に適用されているので、もちろんLEVEL2でもコイン枚数をロードする処理は実行されます。SaveGameオブジェクトは一度生成して保存すると存在し続けます。なので二回目のプレイからはBeginPlayからtrue側の処理、つまりセーブデータをロードする処理が走ってセーブしたコイン枚数「2」をロードします。ロードされた「2」はWBP_PlayerのSetCoinTextによって「0」と「2」を組み合わせて「02」とテキスト表示しています。
🐱これでデータをセーブ,ロードする機能については完成です。
テスト用に配置したコインを削除して、デフォルトのプレイヤースタートに戻しておきましょう。
https://scrapbox.io/files/65d4a6227f91650026a1acff.png
完成!プレイしてみよう!
Deleteキーでセーブデータを削除して最初からプレイしています↓
https://youtu.be/--1IntU1uso
コインを3枚拾った場合は「3」が保存されます。ゲームが開始された時にコイン枚数をロードしてUIに「03」と表示されます。
🐱これで以上になります。また、次回のページでも今回作ったセーブ機能を使ってプレイヤーのライフを実装していきます。お疲れ様でした。