Unityでゲームデータのセーブ・ロードを行う方法

今回はUnityでゲームのデータを保存してみたいと思います。

ゲームのプレイデータを保存出来るようにし、同じ状態で再開出来るというのは今や必須の機能ですね。

昔のゲームみたいにパスワードを入力していく機能を実装するのもある意味面白いとは思いますが・・・・(^_^;)

Unityでゲームデータを扱うのは難しくありません。

スポンサーリンク

Unityでゲームデータを扱う方法

データを保存

↑のようにPlayerPrefsを使うと第1引数で指定した名前のキーを作成し、そこにデータを保存する事が出来ます。

第1引数には保存するデータの名前を指定します。

関数名は保存するデータの形式を指定します。

データの読み出し

値を取り出す時は

とするだけです。

取得したデータをキャラクターのステータススクリプトのHPやMP等のデータに代入し使用します。

データの削除

データを削除する時は

↑のように特定のデータを削除したり、全部のデータを削除する事も出来ます。

ただPlayerPrefs.DeleteAllは使わないでください。Unity自身の設定ファイルが消えてしまいます。

指定したデータが存在するかどうか

データが存在するかどうかは↑のようにHasKeyの引数にデータの名前を指定します。

データが保存されるタイミング

今まで見て来たデータの更新はOnApplicationQuitイベントの中で行われるようです。
OnApplicationQuit関数はアプリケーションが終了する直前に実行されるので途中でゲームが止まってしまった場合はデータの保存がされません。

こういったことがないように

↑のように呼び出すと強制でデータ保存がされるようになります。

ですが、この処理は時間がかかるようでゲームプレイ中にこの処理をさせるのはよくないようです。

詳しくは

https://docs.unity3d.com/ja/current/ScriptReference/PlayerPrefs.html

Unityのスクリプトリファレンスに記載があるので参照してください。

ゲームデータを作り実際に操作してみる

それではこれらの機能を使って実際にデータを保存したり読み出したりしてみたいと思います。

JSONデータについて

単純なデータの保存はさきほど見て来た通りにシンプルに記述すれば出来ますので試してみてください。

今回は保存したいデータをJSON形式で保存したりそのデータを読み出して
再度ゲームデータに戻すという事をしてみたいと思います。

JSON形式はデータの保存方法の1つで

という感じでデータを扱います。

なぜJSON形式でデータを保存するかと言うとオブジェクトのプロパティ値を1つのキーで保存する事が出来る為です。

例えばhp、mpを保存したい場合

と複数の記述が必要ですが、JSON形式のデータはstring型なので一括で保存出来ます。

例えばdata変数に

のようなStringのデータが入っているとすれば

とすればいいので1つ1つのデータを個別に処理する必要がなくなります。

JSON形式でデータの保存と読み出しをする為には保存するデータがSerializable属性で宣言されているオブジェクトに限ります。

Serializable属性はC#だと明示的にしないといけませんがJavaScriptの場合はデフォルトでなっているようです。

また、保存出来るデータはpublic変数のみで、static、privateで宣言されたフィールドはデータ保存されません。

[SerializeField]アトリビュートを付ければprivateで宣言したフィールドも保存出来ます。

それを含めて確認してみます。

JSON形式のデータを作成は自分でJSON形式の文字列を作成してPlayerPrefsに保存し、PlayerPrefsから取得したデータを自分で解析して個々のデータに変換する事も出来ますが、それらを簡単に行う事が出来るクラスがあるのでそれらを使います。

↑のように記述すればJSONデータを扱えます。

ゲームデータを保持し、値を返すSavaDataスクリプトの作成

まずはゲームデータを扱うスクリプトSaveDataを作成しましょう。

objectを継承したクラスとしてSaveDataを作成する為、ゲームオブジェクトに取り付ける事は出来ませんので、後で別のスクリプトからSaveDataクラスのインスタンスを作成します。

明示的にobjectクラスを継承せずとも

上のように書いても自動でobjectクラスが継承される形でクラスが作られます。

static、privateのフィールドが保存されないのを確認する為に宣言しておきます。

また[SerializeField]アトリビュートを付けたprivateフィールドも保存されるかどうか確認します。

スクリプトは長いですが個々の値をセットしたり取得したりするだけがほとんどで、GetNormalDataメソッドは全てのフィールドデータを返し、GetJsonDataはフィールド値をJSON形式にした文字列を返すだけです。

このSaveDataスクリプトで宣言されているhp、mp、power、flag、vector、objをJSON形式のデータに変換しセーブするデータとします。

実際はpublicか[SerializeField]アトリビュートを取り付けたpublicかprivateなフィールドデータしか保存されません。

アクセス修飾子の前にJavaScriptなら@SerializeField、C#なら[SerializeField]でシリアライズ出来るフィールドに出来ます。

SaveDataクラスのインスタンスを生成するCreateNewDataスクリプトの作成

SaveDataスクリプトはobjectクラスを継承して作成したので、ゲームオブジェクトに設定する事が出来ません。

そこで別のCreateNewDataスクリプトを作成し、このスクリプトからSaveDataのインスタンスを作成するようにします。

Startメソッドで適当なSaveDataクラスのインスタンスを作成し、適当なデータを作成して保持します。

SaveDataのフィールドを個別に設定していますが、SaveDataにコンストラクタを作成し設定してもかまいません。

外部スクリプトからSaveDataのデータを取得したい時はGetSaveDataメソッドを使ってアクセスするようにします。

ボタンを押した時に呼び出すスクリプトProcessingUIの作成

次はボタンを押した時、入力フィールドを変更した時に呼び出すスクリプトProcessingUIを作成していきます。

このスクリプトはボタンが押された時や入力フィールドを変更した時にSaveDataスクリプトのデータを整形し、UIテキストに表示する為のものです。

CreateNewDataスクリプトは先ほど作成したスクリプトでここからSaveDataスクリプトを参照するようにしています。

メソッドのそれぞれの役割は、

ResetTextはテキストを空にする。
ShowParameterはSaveDataの全データをそのまま表示する。
ShowJsonDataはSaveDataのJSON形式に変換したデータを表示する。
SaveDataはSaveDataのデータをPlayerPrefsに保存する。
SetHp、SetMp、SetPowerはテキストの値でSaveDataの値を書き換える。
LoadFromJsonOverwriteはPlayerPrefsから取得したデータをSaveDataのデータに上書きする。
CreateDataはPlayerPrefsから取得したデータをSaveDataクラスとして返す。
DeleteDataはPlayerPrefsのデータを削除します。

となります。

これらのメソッドはButtonを押した時やInputFieldを操作した時に呼び出し実行します。

ButtonやInputFieldのUIはこの後作成します。

ゲームデータの確認サンプルUIの作成

ではこれらのスクリプトを実行する為のサンプルを作成していきます。

実際にデータを書き込めるかというサンプルなので詳細な作り方の説明は割愛させて頂きます。

データセーブのサンプルUI

↑のような構成で『データ表示部』『データ入力部』『データ処理ボタン部』とわけて作成します。

データ表示部はデータ処理ボタンが押された時にそのデータを表示する部分です。

データセーブのサンプルUIの実際の画面

構成は↑のようになります。

CanvasにProcessingUIスクリプトとCreateNewDataスクリプトを設定します。

CanvasにProcessingUIとCreateNewDataスクリプトを設定

それぞれ対応するTextやInputFieldを設定し、CreateNewDataのインスペクタではMain Cameraを設定するようにしました。

イベントの設定

ButtonPanelの子要素のボタン群のOn ClickにはProcessingUIスクリプトの対応するメソッドを呼び出すように設定します。

ボタンを押した時のイベントの実行に関しては

UnityのUIのクリックやドラッグのイベントを受け取る
UnityのUIのクリックやドラッグのイベントをEvent Triggerコンポーネントを取りつけて受け取れるようにします

を参照してください。

ShowParameterボタンはShowParameterメソッドを設定。

ShowJSONDataボタンはShowJsonDataメソッドを設定します。

LoadFromJsonOverwriteボタンはLoadFromJsonOverwriteメソッドを設定します。

CreateNewDataボタンはCreateNewDataメソッドを設定します。

SaveボタンはSaveDataメソッドを設定します。

DeleteボタンはDeleteDataメソッドを設定します。

次にInputFieldの入力を終えた時のイベントOnEndEditイベントの所でProcessingUIスクリプトのメソッドを呼び出します。

HPFieldはSetHpメソッドを設定します。

MPFieldはSetMpメソッドを設定します。

PowerFieldはSetPowerメソッドを設定します。

これで機能が完成したので、Unityの実行ボタンを押してデータを確認してみましょう。

↑のようになりました。

ちょっとわかり辛いですが、JSON形式でデータの保存が出来ているのがわかると思います。

長ったらしく書いていますが、JSON形式でまとめて保存しなくても

と個別で保存するのでもいいと思います。

privateやstaticで宣言されたデータは保存されないので間違ってprivateで宣言していてデータを読み出したけど前のデータのままだった
なんて事も起こりえますのでprivateでもデータを保存する場合は[SerializeField]アトリビュートを取り付けておきます。

ゲームデータをゲームフォルダにファイルとして保存する

PlayerPrefsを使うとゲームデータの保存は出来ますが、ゲームフォルダには保存されません。

そこでゲームデータをゲームフォルダ内に指定したファイル名で保存してみたいと思います。

UnityWebplayerやWebGL形式のゲームではファイル操作が出来ないと思うので対象外です(PlayerPrefsを使ってください)。

この処理に関しては

Persistence: Saving and Loading Data - Unity Learn
Do you want to know how to keep your data between scenes? How about between executions of your game? This recorded live session demonstrates how to do both. We ...

を参考にさせて頂きました。

ファイル操作のサンプルUIを作成する

まずはファイル操作をする時に使うUIを作成していきます。

入力フィールドとボタンを作成

↑のようにCanvasを作り、子要素にSaveボタン(UI→Button)、Loadボタン(UI→Button)、Dataフィールド(UI→InputField)を作成します。

入力フィールドとセーブ・ロードボタンの画像

↑がUIの位置を調整した画像です。

LineTypeを変更する

Data(InputField)を選択して、インスペクタのInputFieldのLine TypeをMulti Line Newlineに変更します。

これは入力フィールド内でEnterキーを押して改行した場合に次の行に移りそのまま入力が出来るようにする為です。

データをファイルに保存したり読み出したりするSaveLoadFileスクリプトの作成

それではデータをファイルに保存したり読みだしたりするスクリプトSaveLoadFileを作成します。

ファイルの読み書きをするにはC#のファイル読み書きオブジェクトを使います(Unityのスクリプトファイルには載っていない)。

C#を使ったことがある方は問題はなさそうですね。

行っていることはSaveメソッドが呼ばれた時にApplication.dataPathでゲームフォルダを取得しファイル名を指定してファイルの作成、

保存するデータをBinaryFormatterでシリアライズしてファイルに保存しています。

IOSやAndroidの場合はApplication.persistentDataPathでデバイスのパブリックなディレクトリにアクセス出来るようです。

保存するデータはデータ用クラスを作成し、public変数で宣言したデータを格納するようになっています。

try-catch-finallyは例外処理でファイルを作成する時に例外が発生した時の処理を記述しています(最後のファイル閉じの例外処理してないかも・・・)。

ここら辺はJavaやC#の本を見た方がいいかも・・・(^_^;)

C#でファイルの読み込みと書き込み
C#でファイルの読み込みと書き込みのサンプルを作成していきます。確認にはUnity付属のMonoDevelopを使用します。UnityでCSVファイルの読み込みと書き込みもしてみました。

辺りも参考にしてみてください。

今回作成したSaveメソッドでは常に新しいファイルを作成する仕様になっていますが、ファイルが存在する時は上書きにするといったように書き換えるといいと思います。

Loadメソッドは保存したデータを読み出してデシリアライズし入力フィールドDataに表示しているだけです。

これでスクリプトが出来たので、Canvasにこのスクリプトを設定してください。

SaveLoadFileスクリプトのインスペクタのinputFieldにはData(InputField)を設定してください。

SaveボタンのOnClickイベントにはCanvasのSaveLoadFileスクリプトのSave関数を設定し、
LoadボタンのOnClickイベントにはCanvasのSaveLoadFileスクリプトのLoad関数を設定します。

イベントに関しては

UnityのUIのクリックやドラッグのイベントを受け取る
UnityのUIのクリックやドラッグのイベントをEvent Triggerコンポーネントを取りつけて受け取れるようにします

を参照してください。

ファイルが出力されるか確認する

それではUnityの実行をして確認してみましょう。

ファイルの保存と読み出しのサンプル

↑のように入力フィールドに文字を書いた後Saveボタンを押しファイルに書き込んで入力フィールド内を変更、
そしてLoadボタンを押すと保存したファイルを読み込んで表示する為さきほどの文字列が再び表示されます。

UnityEditorにファイルが作成された

UnityEditorを実行中にApplication.dataPath以下にファイルを作成するとAssets以下にファイルが作成されるので、確認してみてください。

スタンドアロン形式でビルドし、名前をaとするとa.exeとa_Dataというフォルダが同じ階層に出来ます。

ゲームを実行してファイルを作成すると

ファイルが作成された

↑のようにゲームフォルダ(a_Data)以下にゲームデータファイルが作成されていることが確認出来ました。

これでゲームデータをファイルに出力出来ることがわかりました。

終わりに

外部ファイルにデータを保存するのはゲームデータの容量が大きくなった時だと思います。

小規模のゲームならPlayerPrefsを使うだけでいいような気がします。
(PlayerPrefsでデータを保存出来るのは10MBぐらい?)

ファイルを操作するのってなんか怖いですもんね(^_^;)

この記事はずいぶん前に書いた(と言っても2カ月ぐらい前)内容で本日あらためて確認の為に記事を読み直しましたが、なんだかサンプルがわかり辛いですね・・・。

もっと簡単にセーブ、ロードが確認出来るサンプルにすればよかったと思いました。

思ったなら簡単なサンプルを作成せい!(-_-)/~~~ピシー!ピシー!

サンプルの部分を考えなければデータのセーブとロードの部分が楽に出来るというのが解っていただけるかも?

タイトルとURLをコピーしました