Unity编辑器扩展之存储数据
发表于2018-04-18
Unity用来存储数据的PlayerPrefs 类,但在unity编辑器中却有三种方式可以存储数据,下面就和大家介绍下这些存储数据的方式。



EditorPrefs
EditorPrefs可以在PC中存储共享数据,即不受制于项目地存储信息
影响范围
保存的值会影响每一个大版本的Unity编辑器
以前存储在Unity4.x的值只能在Unity 4.x版进行处理,Unity5.x的还可以在Unity 5.x中只处理。

保存什么
应在EditorPrefs存储的窗口的位置和大小,Unity编辑器结构的值等。通过EditorPrefs存储的所有值都以文本形式存储,所以密码等重要信息,请不要保存。
EditorPrefs存储的位置
平台位置
Windows(Unity4.x) HKEY_CURRENT_USER\Software\Unity Technologies\UnityEditor 4.x
Windows(Unity5.x) HKEY_CURRENT_USER\Software\Unity Technologies\UnityEditor 5.x
Mac OS X(Unity4.x) ~/Library/Preferences/com.unity3d.UnityEditor4.x.plist
Mac OS X(Unity5.x) ~/Library/Preferences/com.unity3d.UnityEditor5.x.plist
EditorPrefs为每个主要版本单独保存。Windows将保存在注册表中。如果在Windows通过EditorPrefs存储值,如果出错可能会使Windows无法启动。

当Enable的时候获取保存过的值,在intervalTime改变的时候,保存intervalTime
using UnityEngine; using UnityEditor; public class ExampleWindow : EditorWindow { int intervalTime = 60; const string AUTO_SAVE_INTERVAL_TIME = "AutoSave interval time (sec)"; [MenuItem ("Window/Example")] static void Open () { GetWindow <ExampleWindow> (); } void OnEnable () { intervalTime = EditorPrefs.GetInt (AUTO_SAVE_INTERVAL_TIME, 60); } void OnGUI () { EditorGUI.BeginChangeCheck (); //シーン自動保存間隔(秒) intervalTime = EditorGUILayout.IntSlider ("間隔(秒)", intervalTime, 1, 3600); if (EditorGUI.EndChangeCheck ()) EditorPrefs.SetInt (AUTO_SAVE_INTERVAL_TIME, intervalTime); } }
另外,窗口的尺寸这种重要性不高的值在OnDisable的时候保存比较适合。千万不要在OnGUI中每次保存,OnGUI会被多次调用,负荷很高。
using UnityEngine; using UnityEditor; public class ExampleWindow : EditorWindow { const string SIZE_WIDTH_KEY = "ExampleWindow size width"; const string SIZE_HEIGHT_KEY = "ExampleWindow size height"; [MenuItem ("Window/Example")] static void Open () { GetWindow <ExampleWindow> (); } void OnEnable () { var width = EditorPrefs.GetFloat (SIZE_WIDTH_KEY, 600); var height = EditorPrefs.GetFloat (SIZE_HEIGHT_KEY, 400); position = new Rect (position.x, position.y, width, height); } void OnDisable () { EditorPrefs.SetFloat (SIZE_WIDTH_KEY, position.width); EditorPrefs.SetFloat (SIZE_HEIGHT_KEY, position.height); } }
EditorUserSettings.Set / GetConfigValue
存储可在项目内共享数据的方法。这里保存的值将进行加密,适合于存储诸密码等个人信息。
保存什么
可以用EditorUserSettings来保存用户名和密码,OAuth访问令牌等。
EditorUserSettings.asset是以二进制形式保存的。但使用binary2text还是可以看到内容的。
保存在哪里
保存在项目的Libray目录下的EditorUserSettings.assets中
如何使用
using UnityEditor; public class NewBehaviourScript { [InitializeOnLoadMethod] static void SaveConfig () { EditorUserSettings.SetConfigValue ("Data 1", "text"); } }
为了确保数据被储存,我们可以进入目录查看
CD /Applications/Unity/Unity.app/Contents/Tools ./binary2text /path/to/unityproject/Library/EditorUserSettings.asset
可以看到已经存储成功了:
External References ID: 1 (ClassID: 162) EditorUserSettings m_ObjectHideFlags 0 (unsigned int) m_ConfigValues (map) size 2 (int) data (pair) first "Data 1" (string) second "17544c12" (string) data (pair) first "vcSharedLogLevel" (string) second "0a5f5209" (string) m_VCAutomaticAdd 1 (bool) m_VCDebugCom 0 (bool) m_VCDebugCmd 0 (bool) m_VCDebugOut 0 (bool) m_SemanticMergeMode 2 (int) m_VCShowFailedCheckout 1 (bool)
ScriptableObject
ScriptableObject可以用来存储项目中的共享数据,可用来存储大量数据。
影响范围
ScriptableObject可以创建一个asset,我们可以在Inspector面板中调整数据的值,也可以通过代码进行修改并保存。注意,这是一个asset,所以在游戏运行期间对ScriptableObject的数据修改后数据不会恢复。

using UnityEngine; using UnityEditor; [CreateAssetMenu] public class NewBehaviourScript : ScriptableObject { [Range(0,10)] public int number = 3; public bool toggle = false; public string[] texts = new string[5]; }
保存什么
编辑器扩展创建的数据和配置文件,可以当做一个小型数据库。
保存位置
可以放在Asset目录
JSON如何使用
用法很简单,使用JsonUtility.ToJson和JsonUtility.FromJson。注意:只对序列化字段进行json转换
[Serializable] public class Example { [SerializeField] string name = "hoge"; [SerializeField] int number = 10; } /* 次のJSONデータが出力される { "name": "hoge", "number": 10 } */ Debug.Log(JsonUtility.ToJson(new Example(), true));
JsonUtility和EditorJsonUtility
https://docs.unity3d.com/ScriptReference/JsonUtility.ToJson.html
JsonUtility只支持对MonoBehaviour,ScriptableObject及派生类和普通类进行序列化,而UnityEngine.Object 的子类则不能被其序列化,但我们可以再编辑器中使用EditorJsonUtility来对UnityEngine.Objec的子类进行序列化。
直接序列化数组不会产生包含每个元素的json,而是一个包含了数组对象public域的一个对象json。所以要序列化数组需要把它封装在一个class或struct里面。
使用EditorJsonUtility.toJson来序列化UnityEngine.Object子类
/* 次のような JSON を取得できる {"key名":[{"name":"hoge"},{"name":"hoge"}]} */ public static string ToJson(string key, Object[] objs) { var json = objs.Select(obj => EditorJsonUtility.ToJson(obj)).ToArray(); var values = string.Join(",", json); return string.Format("{\"{0}\":{1}]}", key, values);; }
如果序列化类的字段变量可序列化
对于列表,我们可以创建自己的列表类型, 可以直接对改类型的列表序列化:
/* 使い方は List とほぼ同じ(AddRange がないので自作する) */ [Serializable] public class SerializableList<T> : Collection<T>, ISerializationCallbackReceiver { [SerializeField] List<T> items; public void OnBeforeSerialize() { items = (List<T>)Items; } public void OnAfterDeserialize() { Clear(); foreach (var item in items) Add(item); } } public class Test { [MenuItem("Test/Test")] public static void TestMethod() { var serializedList = new SerializableList<Example> { new Example(), new Example() }; Debug.Log(JsonUtility.ToJson(serializedList)); } } [Serializable] public class Example { [SerializeField] string name = "hoge"; [SerializeField] int number = 10; public string[] var = new string[4]{"1", "2", "3", "4"}; }
输出:
{"items":[{"name":"hoge","number":10,"var":["1","2","3","4"]},{"name":"hoge","number":10,"var":["1","2","3","4"]}]}
我们还可以自定义ToList方法来格式化json
public string ToJson() { var result = "[]" var json = JsonUtility.ToJson(this); var regex = new Regex("^{\"items\":(?<array>.*)}$"); var match = regex.Match(json); if (match.Success) result = match.Groups["array"].Value; return result; }
当然,有了序列化方法,也得有相应的反序列化方法:
public static SerializableList<T> FromJson(string arrayString) { var json = "{\"items\":" + arrayString + "}"; return JsonUtility.FromJson<SerializableList<T>>(json); }
参考:http://anchan828.github.io/editor-manual/web/data_storage.html
来自:https://blog.csdn.net/rickshaozhiheng/article/details/52671333