用意したスクリプト
Jsonファイルの書き込み・読み込みを行うクラス
- ジェネリッククラスにして汎用性が高めました。
- Application.persistentDataPathはセーブするデータのフォルダ名を示しています(処理系により異なる)。
- Save関数でセーブします。
- Load関数でセーブしたデータをロードできますが、セーブデータが存在しない場合はdefaultを返却します。
using UnityEngine; using System.IO; public static class JsonSaveManager<T> { static string SavePath(string path) => $"{Application.persistentDataPath}/{path}.json"; public static void Save(T data, string path) { using (StreamWriter sw = new StreamWriter(SavePath(path), false)) { string jsonstr = JsonUtility.ToJson(data, true); sw.Write(jsonstr); sw.Flush(); } } public static T Load(string path) { if (File.Exists(SavePath(path)))//データが存在する場合は返す { using (StreamReader sr = new StreamReader(SavePath(path))) { string datastr = sr.ReadToEnd(); return JsonUtility.FromJson<T>(datastr); } } //存在しない場合はdefaultを返却 return default; } }
ゲーム開始と同時にデータを読み込み、終了と同時にセーブするためのクラス
- このクラスは記述例であり、実際はプログラム中のTをセーブデータを格納するクラス名に変更するなどの必要があります。
- 先ほど作成したクラス「JsonSaveManager」をゲーム実行中の適切なタイミングで呼び出すためのクラスです。
- Start関数内でLoad関数を呼び出していますが、もちろん他のタイミングでも呼び出せます。
- ゲーム終了と同時にセーブするためにOnApplicationPause(bool isPaused)とOnApplicationQuit()関数を使用しています。両方とも詳細はよくわかりませんが、前者はアンドロイドスマホ、後者はエディタ上での動作の時に必要でした。
using UnityEngine; public class SaveControllerTemplate : MonoBehaviour { public static SaveControllerTemplate I { get; private set; } string saveDataPath = "save-data"; private void Awake() { I = this; } private void Start() { //セーブデータの読み込み T saveData = JsonSaveManager<T>.Load(saveDataPath); if (saveData == null) { //セーブデータが存在しない場合の処理 } else { //セーブデータが存在する場合の処理 } } private void OnApplicationPause(bool isPaused)//アンドロイドスマホではこっちが必要だった { if (isPaused) { OverWriteSaveData(); } } private void OnApplicationQuit()//エディタ上で確認するときはこっちが必要だった { OverWriteSaveData(); } //セーブデータの上書き void OverWriteSaveData() { //新たなセーブデータを作成処理 T saveData = new T(); //既存のセーブデータを上書き JsonSaveManager<TestSaveData>.Save(T, saveDataPath); } }
使用例
用意するスクリプト
用意したスクリプトはシーン上の任意のゲームオブジェクトにアタッチします。
①セーブしたいクラス
- セーブしたいデータを格納したクラスがTestSaveDataです。
- Json形式でデータを保存する場合はセーブしたい変数がいずれもインスペクター上に表示されている必要があるみたいです。そのため変数notSaveは保存されません。
using System.Collections; using System.Collections.Generic; using UnityEngine; using System; [Serializable] public class TestSaveData { public int num; public string str; public Vector3 vec; string notSave = "セーブされない"; } public class TestClass : MonoBehaviour { public int num; public string str; public Vector3 vec; public void SetValue(TestSaveData saveData) { //値TestSaveDataからセット num = saveData.num; str = saveData.str; vec = saveData.vec; } public static TestClass I { get; private set; } private void Awake() { I = this; } }
②「SaveControllerTemplate」を書き換えたクラス
using UnityEngine; public class SaveController : MonoBehaviour { public static SaveController I { get; private set; } string testSaveDataPath = "test-save-data"; private void Awake() { I = this; } private void Start() { TestSaveData saveData = JsonSaveManager<TestSaveData>.Load(testSaveDataPath); if (saveData == null)//セーブデータが存在しない場合は任意の値で初期化 { //新たなセーブデータを作成 saveData = new TestSaveData() { num = 3, str = "テスト", vec = Vector3.one }; } TestClass.I.SetValue(saveData); } private void OnApplicationPause(bool isPaused) { if (isPaused) { OverWriteSaveData(); } } private void OnApplicationQuit()//アプリケーション終了時に呼び出す { OverWriteSaveData(); } //セーブデータの上書き void OverWriteSaveData() { TestSaveData testSaveData = new TestSaveData() { num = TestClass.I.num, str = TestClass.I.str, vec = TestClass.I.vec, }; JsonSaveManager<TestSaveData>.Save(testSaveData, testSaveDataPath); } }
実行結果の確認
まず、セーブデータがない状態で実行すると「TestClass」は次のようになる。
ゲームを中断するとJsonファイルが生成されており、中身を確認すると次のようになっている。確かに、変数notSaveは保存されていないことが確認できる。
{ "num": 3, "str": "テスト", "vec": { "x": 1.0, "y": 1.0, "z": 1.0 } }
次にこの状態からゲームを再実行して「TestClass」を次のように書き換えると、jsonファイルの中身も変化することが確認できる。
{ "num": -1, "str": "書き換え", "vec": { "x": 2.0, "y": -1.0, "z": 5.0 } }
そのあと再実行すると先ほどの画像のように「TestClass」に値が格納される。