據我所知unity Serialization對於基本數據類型很是好用,但處理復類型時就有些基礎缺陷了。
個人需求是鏈接組件和文件並永久保存這種關係。而組件(或遊戲對象)的InstanceID無論用,由於每次場景加載都會不同。
Unity內置的持久化策略是經過「m_LocalIdentfierInFile」(將檢視面板視圖切換爲Debug模式便可看到該字段)來鏈接場景文件和遊戲對象及其組件的(這個確定是Unity的拼寫錯誤,應該是Identifier,固然它也沒有要改正的傾向)。
因此我也能夠利用這個字段來作些什麼啊。但最大的難題是UnityEngine沒有提供任何可使用該字段的接口,也沒說明要如何用,幾番查證得知這是在引擎的C++端實現的。
廢話少說,多方嘗試以後最後想出了一個簡單的解決辦法,就是在編輯器中複製一份「m_LocalIdentfierInFile」,並將其保存爲序列化的屬性。
可是,它對於運行時建立的遊戲對象或組件並無論用。
下面是實現方法 :
- // This is a copy of the "m_localIndentiferInFile"
- // (don't forget to use [Serializable] on the class)
- [SerializeField]
- private int persistentID = -1;
複製代碼
結合下面這段代碼就能夠訪問「m_LocalIdentfierInFile」了,確保該段代碼添加了編輯器預約義宏(#ifdef UNITY_EDITOR),而且不要引用UnityEditor命名空間,不然會致使編譯失敗。
- // Init this instance, it's public so it can be called from a InspectorScript
- // is only set via the unity editor
- public void init ()
- {
- #if UNITY_EDITOR
- PropertyInfo inspectorModeInfo =
- typeof(UnityEditor.SerializedObject).GetProperty ("inspectorMode",
- BindingFlags.NonPublic | BindingFlags.Instance);
- UnityEditor.SerializedObject serializedObject =
- new UnityEditor.SerializedObject (comp);
- inspectorModeInfo.SetValue (serializedObject, UnityEditor.InspectorMode.Debug, null);
- UnityEditor.SerializedProperty localIdProp =
- serializedObject.FindProperty ("m_LocalIdentfierInFile")
- //Debug.Log ("found property: " + localIdProp.intValue);
- persistentID = localIdProp.intValue;
- //Important set the component to dirty so it won't be overriden from a prefab!
- UnityEditor.EditorUtility.SetDirty (this);
- #endif
- }
複製代碼
上面的腳本最初由thelackey3326發佈在Unity論壇中,最後加上一句「UnityEditor.EditorUtility.SetDirty (this);」,以防預製件persistentID被重寫。
下面是在OnEnable()中調用init()方法:
- public void OnEnable ()
- {
- myPersist.init ();
- }
複製代碼
這隻在場景保存後有用(保存以前m_LocalIdentfierInFile == 0),在建立了遊戲對象或拖拽預製件以後保存場景且至少點擊一次遊戲對象!
一般若是將預製件拖拽到場景中,就表示點擊了它並進行了一些操做。
在場景即將保存時能夠訪問其中一些數據,Unity沒有提供保存場景後進行訪問的方法。下面的代碼是在保存場景前調用init()函數:
- static string[] OnWillSaveAssets (string[] paths)
- {
- Object[] objs = Component.FindObjectsOfType (typeof(PersistObject));
- //Debug.Log ("OnWillSaveAssets " + objs.Length);
- foreach (Object obj in objs) {
- PersistObject persist = (PersistObject)obj;
- persist.init ();
- }
- return paths;
- }
複製代碼
以上代碼表示,若是建立一個遊戲對象,並使用編輯器獲取「m_LocalIdentfierInFile」字段,就必須在此以後至少保存兩次場景。第一次是讓Unity設置「m_LocalIdentfierInFile」,第二次是將其保存到局部變量中。這並不是最便捷的方法,但也夠用了,只需使用持久化的遊戲對象設置下場景就好。