Unity序列化和持久化

據我所知unity Serialization對於基本數據類型非常好用,但處理復類型時就有些基礎缺陷了。

我的需求是連接組件和文件並永久保存這種關係。而組件(或遊戲對象)的InstanceID不管用,因爲每次場景加載都會不一樣。

Unity內置的持久化策略是通過“m_LocalIdentfierInFile”(將檢視面板視圖切換爲Debug模式即可看到該字段)來連接場景文件和遊戲對象及其組件的(這個肯定是Unity的拼寫錯誤,應該是Identifier,當然它也沒有要改正的傾向)。

所以我也可以利用這個字段來做些什麼啊。但最大的難題是UnityEngine沒有提供任何可以使用該字段的接口,也沒說明要如何用,幾番查證得知這是在引擎的C++端實現的。

廢話少說,多方嘗試之後最後想出了一個簡單的解決辦法,就是在編輯器中複製一份“m_LocalIdentfierInFile”,並將其保存爲序列化的屬性。

但是,它對於運行時創建的遊戲對象或組件並不管用。

下面是實現方法  :

  1. // This is a copy of the "m_localIndentiferInFile"
  2. // (don't forget to use [Serializable] on the class)
  3. [SerializeField]
  4. private int persistentID = -1;
複製代碼

結合下面這段代碼就可以訪問“m_LocalIdentfierInFile”了,確保該段代碼添加了編輯器預定義宏(#ifdef UNITY_EDITOR),並且不要引用UnityEditor命名空間,否則會導致編譯失敗。

  1. // Init this instance, it's public so it can be called from a InspectorScript
  2. // is only set via the unity editor
  3. public void init ()
  4. {
  5.     #if UNITY_EDITOR
  6.     PropertyInfo inspectorModeInfo =
  7.     typeof(UnityEditor.SerializedObject).GetProperty ("inspectorMode",
  8.     BindingFlags.NonPublic | BindingFlags.Instance);

  9.     UnityEditor.SerializedObject serializedObject = 
  10.     new UnityEditor.SerializedObject (comp);

  11.     inspectorModeInfo.SetValue (serializedObject, UnityEditor.InspectorMode.Debug, null);

  12.     UnityEditor.SerializedProperty localIdProp =
  13.     serializedObject.FindProperty ("m_LocalIdentfierInFile")  

  14.     //Debug.Log ("found property: " + localIdProp.intValue);

  15.     persistentID = localIdProp.intValue;
  16.     //Important set the component to dirty so it won't be overriden from a prefab!
  17.     UnityEditor.EditorUtility.SetDirty (this);
  18.     #endif
  19. }
複製代碼

上面的腳本最初由thelackey3326發佈在Unity論壇中,最後加上一句“UnityEditor.EditorUtility.SetDirty (this);”,以防預製件persistentID被重寫。

下面是在OnEnable()中調用init()方法:

  1. public void OnEnable ()
  2. {
  3.     myPersist.init ();
  4. }
複製代碼

這隻在場景保存後有用(保存之前m_LocalIdentfierInFile == 0),在創建了遊戲對象或拖拽預製件之後保存場景且至少點擊一次遊戲對象!

通常如果將預製件拖拽到場景中,就表示點擊了它並進行了一些操作。
 

在場景即將保存時可以訪問其中一些數據,Unity沒有提供保存場景後進行訪問的方法。下面的代碼是在保存場景前調用init()函數:

  1. static string[] OnWillSaveAssets (string[] paths)
  2.     {
  3.         Object[] objs = Component.FindObjectsOfType (typeof(PersistObject));
  4.         //Debug.Log ("OnWillSaveAssets " + objs.Length);
  5.         foreach (Object obj in objs) {
  6.                 PersistObject persist = (PersistObject)obj;
  7.                 persist.init ();
  8.         }

  9.         return paths;
  10.     }
複製代碼

完整源碼點此鏈接

以上代碼表示,如果創建一個遊戲對象,並使用編輯器獲取“m_LocalIdentfierInFile”字段,就必須在此之後至少保存兩次場景。第一次是讓Unity設置“m_LocalIdentfierInFile”,第二次是將其保存到局部變量中。這並非最便捷的方法,但也夠用了,只需使用持久化的遊戲對象設置下場景就好。
 

原文地址:http://bbs.a-coder.cn/thread-8-1-1.html




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章