Unity - JsonUtility:データをJSONに変換し、セーブ・ロードする -
初めに
データを保存する方法の一つとして、JSON ファイルに変換し、保存する方法があります。そこで使用される JsonUtility についてまとめます。
Index
JSON とは
JSON ファイルは JavaScript Object Notation の略で JavaScript のデータ定義文をベースとした、簡易的なデータ定義言語です。
今回はデータを JSON ファイルに書き出したり、読み込んだりすることで、セーブ、ロードをすることを目指します。
JSON の記入例
[ {"id" : "1", "name" : "tanaka"}, {"id" : "2", "name" : "nakata"} ]
(主な記述のルール)
- キーをダブルクォーテーションで囲む
- キーと値をコロンで区切る
- 複数の組み合わせを記述する場合はカンマで区切る
JSON の説明は下のリンク先をご覧ください。
www.tohoho-web.com
JsonUtility とは
Unity 上で Json ファイルを扱う機能になります。
できることは下記の3つになります。
JsonUtility を使ってセーブ・ロードする
今回はステータスを作ってみます。完成品のスクリプトを載せておきます。
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEditor; //AssetDatabaseを使うために追加 using System.IO; //StreamWriterなどを使うために追加 using System.Linq; //Selectを使うために追加 public class JsonScript : MonoBehaviour { //保存先 string datapath; void Awake() { //保存先の計算をする //これはAssets直下を指定. /以降にファイル名 datapath = Application.dataPath + "/TestJson.json"; } // Start is called before the first frame update void Start() { //playerデータを取得 Player player = new Player (); //JSONファイルがあればロード, なければ初期化関数へ if(FindJsonfile()) { player = loadPlayerData(); } else { Initialize(player); } } //セーブするための関数 public void savePlayerData(Player player) { StreamWriter writer; //playerデータをJSONに変換 string jsonstr = JsonUtility.ToJson (player); //JSONファイルに書き込み writer = new StreamWriter(datapath, false); writer.Write (jsonstr); writer.Flush (); writer.Close (); } //JSONファイルを読み込み, ロードするための関数 public Player loadPlayerData() { string datastr = ""; StreamReader reader; reader = new StreamReader (datapath); datastr = reader.ReadToEnd (); reader.Close (); return JsonUtility.FromJson<Player> (datastr); } //JSONファイルがない場合に呼び出す初期化関数 //初期値をセーブし, JSONファイルを生成する public void Initialize(Player player) { player.name = "aaa"; player.hp = 12; player.attack = 6; player.defense = 5; savePlayerData(player); } //JSONファイルの有無を判定するための関数 public bool FindJsonfile() { string[] assets = AssetDatabase.FindAssets(datapath); Debug.Log(assets.Length); if(assets.Length != 0) { string[] paths = assets.Select(guid => AssetDatabase.GUIDToAssetPath(guid)).ToArray(); Debug.Log($"検索結果:\n{string.Join("\n", paths)}"); return true; } else { Debug.Log("Jsonファイルがなかった"); return false; } } } //Playerのデータとなるクラスの定義 [System.Serializable] public class Player { public string name; public int hp; public int attack; public int defense; }
初めて実行したときは、JSONファイルはまだ作られていません。そのため、Initialize 関数に入り、初期値が代入されます。そして、savePlayerData が実行され JSONファイルが作られます。
2回目以降は、JSONファイルがすでにあるため、loadPlayerData に入り、ロードされます。
(実行前)
(実行後)
JSON ファイルが生成され、初期値がJSONファイルに保存されていることがわかります。
保存したいデータを記述
保存したいデータのクラスを定義する必要があります。今回のスクリプトでは Player のクラスに当たる部分です。
//Playerのデータとなるクラスの定義 [System.Serializable] public class Player { public string name; public int hp; public int attack; public int defense; }
Application.dataPath
プラットフォームごとのデータの保存先を返します。
datapath = Application.dataPath + "/TestJson.json";
StreamWriter、StreamReader
テキストファイルにデータを書き込んだり、読み込んだりするための関数です。
名前空間に "using System.IO;" を追加することで使えます。詳細は下のリンク先をご覧ください。
AssetDataBase
AssetDataBase はアセットにアクセスし、操作するためのインターフェースです。
名前空間に "using UnityEditor;" を追加することで使えます。
今回使った "FindAssets" はフィルター検索の文字列を使ってアセットデータベースを検索します。
public static string FindAssets (string filter);
今回はファイルの有無だけ判定できればよいので、string の長さが 0 であればファイルがないと判定しています。
//JSONファイルの有無を判定するための関数 public bool FindJsonfile() { string[] assets = AssetDatabase.FindAssets(datapath); Debug.Log(assets.Length); if(assets.Length != 0) { string[] paths = assets.Select(guid => AssetDatabase.GUIDToAssetPath(guid)).ToArray(); Debug.Log($"検索結果:\n{string.Join("\n", paths)}"); return true; } else { Debug.Log("Jsonファイルがなかった"); return false; } }
細かい使い方は下のサイトで分かりやすく説明してくださっています。
www.urablog.xyz
docs.unity3d.com
docs.unity3d.com
JsonUtility を使う上での注意点
List や Dictionary などが直接使えない
マニュアルを見ると、サポートする型の部分に「プリミティブ型や配列など、他の型を直接 API に渡すことは現在サポートされていません。それらの型は、クラスや構造体などの型にラップする必要があります。」と書かれています。
docs.unity3d.com
つまり、List や Dicitionary などの型は対象外となり、直接は使えないことがわかります。
試しに List が含まれる下のクラスを JSON に変換してみると、次のようになります。
//Playerのデータとなるクラスの定義 [System.Serializable] public class Player { public string name; public int hp; public int attack; public int defense; public List<int[]> list; }
list のデータがちゃんと保存されていないことがわかります。(エラーは吐きませんでした)
最後に
JsonUtility とファイルに読み書きするための StreamWriter、StreamReader を使っています。Playerクラスの中身を変えれば、使いまわせると思います。