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