Unityでデータを量産する場合、ScriptableObject は大変便利です。
[CreateAssetMenu(fileName = "SampleDataSO", menuName = "ScriptableObject/SampleDataListSO")]
public class SampleDataSO : ScriptableObject
{
public SampleData[] samples;
}
上記のようなScriptableObjectであれば
Create> ScriptableObject> SampleDataListSO
でオブジェクトを作成することができ、直接データを作っていくことができます。
作成したデータをそのまま利用する場合は問題ないのですが、JSON経由でやりとりしたい場合、ScriptableObjectはCreateInstance<>()
でインスタンスを生成する必要があるため、通常のデータクラスのように
SampleDataSO data = JsonUtility.FromJson<SampleDataSO>(jsonString);
とすると
Failed to load settings data: Cannot deserialize JSON to new instances of type 'SampleDataSO.'
といったエラーが出てしまいます。
そこでScriptableObjectでは
JsonUtility.FromJsonOverwrite(json, data);
を使用します。
SampleDataSO.cs
using JetBrains.Annotations;
using UnityEngine;
[System.Serializable]
public class PersonData
{
public string name;
public int age;
}
[System.Serializable]
public class HobbyData
{
public string hobby;
public float hours;
}
[System.Serializable]
public class SampleData
{
public PersonData person;
public HobbyData[] hobbies;
}
[CreateAssetMenu(fileName = "SampleDataSO", menuName = "ScriptableObject/SampleDataListSO", order = 1)]
public class SampleDataSO : ScriptableObject
{
public SampleData[] samples;
// ScriptableObjectをCreateInstance()するにはJsonUtility.FromJsonOverwriteが必要
public static SampleDataSO CreateScriptableObjectFromJSON(string jsonString)
{
SampleDataSO data = CreateInstance<SampleDataSO>();
JsonUtility.FromJsonOverwrite(jsonString, data);
return data;
}
}
以下のサンプルは、上記ScriptableObjectをJSON形式でファイルに保存し、再びScriptableObjectに戻します。
ScriptableObjectJSONSample.cs
using System;
using UnityEngine;
public class ScriptableObjectJSONSample : MonoBehaviour
{
[SerializeField] string m_dataPath = "SampleData.json";
[SerializeField] SampleDataSO m_sampleDataSO;
// Start is called before the first frame update
void Start()
{
SaveToJSON(m_dataPath, m_sampleDataSO);
SampleDataSO importedDataSO = LoadfromJSONFile(m_dataPath);
string jsonStr = JsonUtility.ToJson(importedDataSO, true);
Debug.Log("ImportedData: \n" + jsonStr);
}
// Update is called once per frame
void Update()
{
}
public static string GetFullPath(string _dataPath)
{
#if !UNITY_EDITOR
string appPath = Application.persistentDataPath;
#else
string appPath = Application.dataPath;
#endif
return $"{appPath}/{_dataPath}";
}
public static bool SaveToJSON(string _dataPath, SampleDataSO _dataSO)
{
bool result = false;
string fullPath = GetFullPath(_dataPath);
// ファイルにデータを書き込む
string jsonStr = JsonUtility.ToJson(_dataSO, true);
Debug.Log("SaveSettings: " + fullPath);
try
{
System.IO.File.WriteAllText(fullPath, jsonStr);
result = true;
}
catch (Exception e)
{
Debug.LogError("Failed to save settings data: " + e.Message);
}
return result;
}
public static SampleDataSO LoadfromJSONFile(string _dataPath)
{
string fullPath = GetFullPath(_dataPath);
// ファイルからデータを読み込む
string jsonStr = System.IO.File.ReadAllText(fullPath);
try
{
SampleDataSO data = SampleDataSO.CreateScriptableObjectFromJSON(jsonStr);
return data;
}
catch (Exception e)
{
Debug.LogError("Failed to load settings data: " + e.Message);
return null;
}
}
}
結果:
ImportedData:
{
"samples": [
{
"person": {
"name": "アンドリュー",
"age": 64
},
"hobbies": [
{
"hobby": "彫刻",
"hours": 6.0
},
{
"hobby": "自分探しの旅",
"hours": 1.0
}
]
},
{
"person": {
"name": "ポーシャ",
"age": 32
},
"hobbies": [
{
"hobby": "ピアノ演奏",
"hours": 2.0
}
]
}
]
}