ひとりでのアプリ開発 - fineの備忘録 -

ひとりでアプリ開発をするなかで起こったことや学んだことを書き溜めていきます

Unity - EditorJsonUtility:Prehab などの UnityEngine.Object のデータを保存する -

初めに

 データのセーブ・ロードに JsonUtility が用いられますが、似たような機能に EditorJsonUtility が存在します。EditorJsonUtility についてまとめます。

前提知識:JsonUtility について

 以前、記事にしてまとめましたので、そちらをご覧ください。

fineworks-fine.hatenablog.com

JsonUtility との違い

UnityEngine.Object のシリアライズ、デシリアライズについて

 結論から述べると

アセットを参照する場合は、JsonUtility ではなく、EditorJsonUtility を用いる

 Prehab のデータを参照し、JSON に保存します。
 次のスクリプトをゲームオブジェクトにつけ、実行してみます。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;  //AssetDatabaseを使うために追加
using System.IO;  //StreamWriterなどを使うために追加
using System.Linq;  //Selectを使うために追加

public class EditorJsonScript : MonoBehaviour
{
    //保存先
    string[] datapath;

    //初期値で保存するオブジェクト
    public GameObject _obj;

    void Awake()
    {
      //保存先の計算をする
      //これはAssets直下を指定. /以降にファイル名
      datapath = new string[2];
      datapath[0] = Application.dataPath + "/TestJsonUtility.json";
      datapath[1] = Application.dataPath + "/TestEditorJsonUtility.json";
    }

    // Start is called before the first frame update
    void Start()
    {
      //playerデータを取得
      Obj obj = new Obj ();

      //JSONファイルがあればロード, なければ初期化関数へ
      if(FindJsonfile())
      {
        obj = loadPlayerData();
      }
      else
      {
        Initialize(obj);
      }
    }

    //セーブするための関数
    public void savePlayerData(Obj obj)
    {
      StreamWriter writer;

      //playerデータをJSONに変換
      string jsonstr = JsonUtility.ToJson (obj);
      string edijsonstr = EditorJsonUtility.ToJson (obj);

      Debug.Log("jsonstr:" + jsonstr);
      Debug.Log("edijsonstr:" + edijsonstr);

      //JSONファイルに書き込み
      for(int i = 0; i < datapath.Length; i++)
      {
        writer = new StreamWriter(datapath[i], false);
        writer.Write (jsonstr);
        writer.Flush ();
        writer.Close ();
      }
    }

    //JSONファイルを読み込み, ロードするための関数
    public Obj loadPlayerData()
    {
      string datastr = "";
      StreamReader reader;
      reader = new StreamReader (datapath[0]);
      datastr = reader.ReadToEnd ();
      reader.Close ();

      return JsonUtility.FromJson<Obj> (datastr);
    }

    //JSONファイルがない場合に呼び出す初期化関数
    //初期値をセーブし, JSONファイルを生成する
    public void Initialize(Obj obj)
    {
      obj.obj = _obj;

      savePlayerData(obj);
    }

    //JSONファイルの有無を判定するための関数
    public bool FindJsonfile()
    {
      string[] assets = AssetDatabase.FindAssets(datapath[0]);
      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 Obj
{
    public GameObject obj;
}

(実行結果)

 この結果からわかることは次の通りです。

JsonUtility インスタンスIDをシリアライズ
EditorJsonUtility GUIDをもとにシリアライズ

 インスタンスIDはインスタンス生成時に生成されるため、再起動した場合、インスタンスIDは変わってしまいます。そのため、アセットから正しく参照できません。
 Prehab を使うなどアセットを参照する場合は、EditorJsonUtility を用いたほうがよいでしょう。

関数の違い

 JsonUtility は次の3つの関数を使うことができました。

  • FromJson:JSONから変換する
  • FromJsonOverwrite:JSON ファイルから既存のオブジェクトに値を上書きする
  • ToJson:JSONファイルに変換する

しかし、

EditorJsonUtility は FromJson を使うことができない

最後に

 JsonUtility はバックグランドスレッドで使えるが、EditorJsonUtility はバックグランドスレッドで使えないという違いもあるようです。