Unity 2019.2.0f1 Personal(2019年8月)
今回はJsonテキストをローカルに保存していきます〜
JsonUtilityでクラスをJsonテキストに変換しローカルに保存したり、
逆に読み出して使用したりします。
※iOSやAndroidではなくUnity Editor環境での保存です。
Save機能
まずはデータの保存、Save機能を作成していきます〜
使いやすいstaticクラスで作成していきます。
using System; using System.IO; using System.Collections; using System.Collections.Generic; using UnityEngine; public static class SaveDataManager { const string SAVE_FILE = "save_data.json"; const string DATA_DIR = "Assets/StreamingAssets/data/"; static string saveDataPath; public static SaveData saveData; public static void Init() { saveDataPath = Path.Combine(DATA_DIR + SAVE_FILE); } public static void Save() { if (!Directory.Exists(DATA_DIR)) { Directory.CreateDirectory(DATA_DIR); } var json = JsonUtility.ToJson(saveData); StreamWriter writer = new StreamWriter(saveDataPath, false); writer.WriteLine(json); writer.Flush(); writer.Close(); } [Serializable] public class SaveData { [SerializeField] private string name; public string Name { get { return name; } private set { name = value; } } [SerializeField] private int level; public int Level { get { return level; } private set { level = value; } } [SerializeField] private long money; public long Money { get { return money; } private set { money = value; } } public void SetName(string name) { Name = name; } public void SetLevel(int level) { Level = level; } public void SetMoney(long money) { Money = money; } public void Init() { Name = "名無し"; Level = 1; Money = 500; } } }
SaveDataManager.cs
InitメソッドのPath.Combineは、データ保存先のPathとファイル名を結合してくれます。
saveDataPathの中身は"Assets/StreamingAssets/data/save_data.json"となります。
一番下にあるSaveDataクラスがJsonにシリアライズされ保存されます。
[SerializeField]のついた変数name, level, moneyがJsonとなり、
プロパティName, Level, MoneyはJsonにはなりません。
プロパティのsetアクセサはprivateとなっているため
データ設定にはSet系のメソッドを経由する必要があります。
最後にSaveメソッドです。
DATA_DIR("Assets/StreamingAssets/data/")のディレクトリが存在しない場合、CreateDirectoryで作成してくれます。
JsonUtility.ToJsonで、メンバ変数にあるSaveDataクラスのデータをJsonに変換します。
データが用意されたので保存していきます。
StreamWriterオブジェクトはテキストの内容を保存する時に使われます。
第一引数に保存先のPathをテキスト名まで入れて指定します。
第二引数(bool)はappend(上書き)するかで、trueだと追記、falseだと上書きとなります。
セーブするたびに次の行へ追記されていっても仕方がないので、falseにします。
続いてStreamWriterのWriteLineメソッドで実際にデータの書き出しを行います。
WriteLineの時点ではデータをバッファに移しただけで、それを順次ファイルに書き出していきます。
StreamWriterのFlushメソッドを実行することで、バッファに残っているデータを全て書き出します。
最後にCloseメソッドでStreamWriterを閉じます。
Stream系のオブジェクトはちゃんとCloseしないとファイルが正常に保存されなかったりするので注意。
Load機能
続いて保存したデータを呼び出すLoad機能です。
using System; using System.IO; using System.Collections; using System.Collections.Generic; using UnityEngine; public static class SaveDataManager { const string SAVE_FILE = "save_data.json"; const string DATA_DIR = "Assets/StreamingAssets/data/"; static string saveDataPath; public static SaveData saveData; public static void Init() { saveDataPath = Path.Combine(DATA_DIR + SAVE_FILE); // ***** 開始 ***** Load(); // ***** 終了 ***** } // ***** 開始 ***** public static void Load() { if (File.Exists(saveDataPath)) { FileStream stream = File.Open(saveDataPath, FileMode.Open); StreamReader reader = new StreamReader(stream); var json = reader.ReadToEnd(); reader.Close(); stream.Close(); saveData = JsonUtility.FromJson<SaveData>(json); } else { saveData = new SaveData(); saveData.Init(); Save(); } } // ***** 終了 ***** public static void Save() { if (!Directory.Exists(DATA_DIR)) { Directory.CreateDirectory(DATA_DIR); } var json = JsonUtility.ToJson(saveData); StreamWriter writer = new StreamWriter(saveDataPath, false); writer.WriteLine(json); writer.Flush(); writer.Close(); } [Serializable] public class SaveData { [SerializeField] private string name; public string Name { get { return name; } private set { name = value; } } [SerializeField] private int level; public int Level { get { return level; } private set { level = value; } } [SerializeField] private long money; public long Money { get { return money; } private set { money = value; } } public void SetName(string name) { Name = name; } public void SetLevel(int level) { Level = level; } public void SetMoney(long money) { Money = money; } public void Init() { Name = "名無し"; Level = 1; Money = 500; } } }
SaveDataManager.cs
Loadメソッドの最初ではsaveDataPathにファイルが存在するか判定しています。
存在していたらファイルを読み出しし、
存在していなければSaveDataクラスをnewし初期値を設定し、先ほどのSaveメソッドで保存します。
FileStreamはファイルを読み込む際に使うオブジェクトです。
FileStreamはFile.Openメソッドで作成します。
読み込みファイルのPathを第一引数に、FileModeを第二引数にとります。
FileMode.Openは既存のファイルを開く際に指定します。他にはファイルを新規作成して開くFileMode.Createなどあります。
続いて作成したFileStreamを引数にとりStreamReaderオブジェクトを作成し、
StreamReaderのReadToEndメソッドによりsaveDataPathにあるファイルのデータを全て読み出します。
使用したストリーム系オブジェクト(FileStreamとStreamReader)はCloseします。
最後にJsonUtility.FromJsonにより、Jsonテキストからクラスへ変換します。
ジェネリクス
Initメソッドに今回作成したLoadメソッドを追記しておきます。
実行
別オブジェクトを作成しSaveDataManagerのInitメソッドを実行することで、
実際にsave_data.jsonファイルを作成しデータのセーブ/ロードを行います。
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Manager : MonoBehaviour { void Start() { SaveDataManager.Init(); CheckStatus(); SaveDataManager.saveData.SetName("たろう"); SaveDataManager.saveData.SetLevel(100); SaveDataManager.saveData.SetMoney(10000000); SaveDataManager.Save(); CheckStatus(); } void CheckStatus() { Debug.Log("name:" + SaveDataManager.saveData.Name + " level:" + SaveDataManager.saveData.Level + " money:" + SaveDataManager.saveData.Money); } }
Manager.cs
SaveDataManagerのInitメソッドを実行するとLoadメソッドが実行されます。
まだsave_data.jsonファイルは存在しないので、
SaveDataクラスを生成しSaveメソッドを実行します。
Saveメソッドを通してディレクトリが作成され、ローカルに保存されます。
セーブデータの更新はSaveDataManager.saveData(SaveDataクラス)を通して行います。
具体的にはSaveDataクラスのSet系メソッドです。
更新する値のセットが完了っしたらSaveメソッドを実行し、データを保存します。
ゲームモードを終了してもjsonファイルが残っていることが確認できます。
以上、JsonUtilityを使ったデータの保存についてでした。
ありがとうございました〜