1. 程式人生 > >在Unity3D中使用ScriptableObject進行序列化

在Unity3D中使用ScriptableObject進行序列化

ScriptableObject型別經常用於儲存一些Unity3D本身不可以打包的一些object,比如字串,一些類物件等。用這個型別的子型別,則可以用BuildPipeline打包成assetbundle包供後續使用,非常方便。這樣除了playerpref和c#檔案讀取外,另外的一種存取一些資料物件的方法

[csharp]  view plain  copy  print ?
  1. using UnityEngine;   
  2.   
  3. public class XMLContains : ScriptableObject   
  4.   
  5. {   
  6.   
  7.     public string theXML;   
  8.   
  9. }   



By making your class enherit from ScriptableObject, it becomes an "Asset Type" to unity, in the sense that you can store them on disk, and use the Unity IDE interface to drag it from the assetsfolder to a behaviour or whatever. It also automatically plays nice with Unity's dependency tracking system that decides what does and what does not 

Go into a webplayer. Going a bit further with this example, you could have let's say a TieFighter class, actually get some of its information (max health, max speed, acceleration), from your xml file, by making the TieFighter class look like this:
 

[csharp]  view plain
 copy  print ?
  1. using UnityEngine;   
  2.   
  3. public class TieFighter : MonoBehaviour   
  4.   
  5. {   
  6.   
  7.      public XMLContainer myXMLSettings;   
  8.   
  9.    
  10.   
  11.      void Awake()   
  12.   
  13.      {   
  14.   
  15.         //parse myXMLSettings.theXML into reasonable data   
  16.   
  17.      }   
  18.   
  19.    
  20.   
  21.      void Update()   
  22.   
  23.      {   
  24.   
  25.         //use the reasonable data   
  26.   
  27.      }   
  28.   
  29.  }  


 

You could then attach the TieFighter script to a gameobject, and then drag your xml-asset from your assetsfolder onto the myXMLSettings public field.Please note that this example is much better at showing how you could use a ScriptableObject than how to properly implement a TieFighter, as I would never really have that parse an actual xml file on runtime. Tiefighters are too cool for xml anyway.
以上是不做成bundle包的形式,下面提供了一種打包成bundle資源,通過www來進行載入的方案:

通常,可以用BuildPipeline.BuildAssetBundle打包資源,這些資源包括模型、紋理、貼圖等。其實也可以打包ScriptableObject,而ScriptableObject中可以儲存任何資料型別。

以下為一個完整示例。

 

1、先建立一個類:

[csharp]  view plain  copy  print ?
  1. using UnityEngine;   
  2.   
  3. using System.Collections.Generic;    
  4.   
  5. public class SysData : ScriptableObject   
  6.   
  7. {                 
  8.   
  9. public List<Vector3> content;   
  10.   
  11. }  


 

該類只有一個屬性content。當然也可以宣告更多屬性、事件和方法。

在後面,這個類的例項將作為資源被打包。

 

2、建立一個編輯器指令碼:

該指令碼用於例項化SysData,設定一些資料,然後打包。

 

[csharp]  view plain  copy  print ?
  1. using UnityEngine;   
  2.   
  3. using UnityEditor;   
  4.   
  5. using System.Collections.Generic;    
  6.   
  7. public class Export  
  8.   
  9. {          
  10.   
  11.   [MenuItem("Assets/Export")]           
  12.   
  13.   public static void Execute()   
  14.   
  15.   {                
  16.   
  17.    //例項化SysData               
  18.   
  19.    SysData sd = ScriptableObject.CreateInstance<SysData>();                             
  20.   
  21.     //隨便設定一些資料給content                 
  22.   
  23.     sd.content = new List<Vector3>();                 
  24.   
  25.     sd.content.Add(new Vector3(1,2,3));                 
  26.   
  27.     sd.content.Add(new Vector3(4,5,6));                              
  28.   
  29.     // SysData將建立為一個物件,這時在project面板上會看到這個物件。                 
  30.   
  31.     string p = "Assets/SysData.asset";           
  32.   
  33.     AssetDatabase.CreateAsset(sd, p);                 
  34.   
  35.     Object o = AssetDatabase.LoadAssetAtPath(p, typeof(SysData));                              
  36.   
  37.     //打包為SysData.assetbundle檔案。                 
  38.   
  39.     BuildPipeline.BuildAssetBundle(o, null"SysData.assetbundle");                 
  40.   
  41.     //刪除面板上的那個臨時物件               
  42.   
  43.      AssetDatabase.DeleteAsset(p);                        
  44.   
  45.   }   
  46.   
  47. }   
  48.   
  49.    

 

3、執行時載入這個資料資源。

[csharp]  view plain  copy  print ?
  1. IEnumerator Start ()   
  2. {                
  3.  WWW www = new WWW("file://" + Application.dataPath + "/../SysData.assetbundle");                
  4.  yield return www;    
  5.                
  6.  //轉換資源為SysData,這個sd物件將擁有原來在編輯器中設定的資料。                
  7.  SysData sd = www.assetBundle.mainAsset as SysData;   
  8.  //如列印sd.content[0],將得到Vector3(1,2,3);               
  9.  print(sd.content[0]);  
  10. }  


 

4、這其實是把整個物件例項打包,如果ScriptableObject屬性中包括其他的類例項,則這些類需加上[Serializable]序列化。通過這種方法,可以將系統需要的資料(如角色分類、matrix4x4資料等等)打包,載入後直接轉換為預定的型別,具有更高的效率。