ScriptableObject

什麼是ScriptableObject?

點擊查看Unity官網的描述html

直譯過來就是「腳本化對象」,換言之這類做爲存儲結構化的數據來使用,並寫入Unity的資源.asset文件去存儲一組數據,取用的時候直接做爲一個數據對象拿來用,很方便。git

ScriptableObject 有什麼好處?

  • Unity用於建立不須要綁定到物體的對象,即非繼承於Mono,該類繼承於UnityEngine.Object
  • 存放編輯器或數據配置文件
  • 方便操做管理,能夠可視化編輯
  • 取數據方便,ScriptableObject已是可序列化的數據,不用像讀取純文本或xml那樣還要繁瑣耗時的數據解析過程

不過根據近期使用發現它也有一些不足

  • 雖然編輯可視化,但受限於數據量,存放的數據太多的時候,閱讀就不直觀了,如圖數據多了想編輯須要一項項展開,查找也不方便, 
    image 
    這裏寫圖片描述

針對ScriptableObject的內容多時編輯不直觀的狀況,最好是數據源頭管理出發修編輯修改數據,如數據來源於管理器建立、.txt、數據庫、Excel表等等,最好直接去修改原數據。 我嘗試了寫一個GUI數據編輯器,結果就是更噁心更不直觀。github

ScriptableObject怎麼用?

對象建立

以下是我聲明的一個繼承自 ScriptableObject 的類 MyScriptableObject,其中我還想序列化一些自定義的數據結構數據庫

using System.Collections.Generic; public class MyScriptableObject : UnityEngine.ScriptableObject { public string testName = ""; //注意:基本數據類型之外的成員類型須要加 SerializeField 關鍵字 [UnityEngine.SerializeField] public List<MyDataInfo> myData = new List<MyDataInfo>(); } //注意:自定義數據類型被ScriptableObject對象使用的時候,該類須要加 Serializable 關鍵字 [System.Serializable] public class MyDataInfo { public int dataNumber = 0; public string dataStr = ""; public MyDataInfo(int dataNumber,string dataStr) { this.dataNumber = dataNumber; this.dataStr = dataStr; } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

那麼問題來了,怎麼編輯使用這個類呢?你能夠把它當作一個普通的Object子對象去使用,也能夠實例出來並存放到.asset文件中去做爲一個數據體,以下建立asset文件數據結構

MyScriptableObject nameInfoObj = ScriptableObject.CreateInstance<MyScriptableObject>(); nameInfoObj.testName = "測試名字"; nameInfoObj.name = "MyScriptableObject"; nameInfoObj.myData.Add(new MyDataInfo(100, "myData測試")); nameInfoObj.myData.Add(new MyDataInfo(101, "myData3測試")); UnityEditor.AssetDatabase.CreateAsset(nameInfoObj, "Assets/" + nameInfoObj.name + ".asset");
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

對象加載使用

  • 直接加載 ScriptableObject 對象,其中具體的「ScriptableObject」能夠是繼承自ScriptableObject的實際對象類型,我之因此這麼寫是由於這樣寫相對保險:
string path = Application.dataPath+"/aaaaa.asset"; UnityEngine.Object[] loadList = AssetDatabase.LoadAllAssetsAtPath(path); if(loadList[0] == null) { //TOOD這裏考慮路徑有效的狀況下,但拿到的asset內容資源無效,丟失了綁定的腳本 } ScriptableObject dataInfo = loadList[0] as ScriptableObject;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

否則若是讀一樣的文件內容如下方式,就有可能報錯了,如我換用如下這兩種寫法,Unity就回拋出一個警告,所以不提倡如下的寫法編輯器

ScriptableObject dataInfo = AssetDatabase.LoadAssetAtPath<ScriptableObject>(assetPath);

 ScriptableObject dataInfo = AssetDatabase.LoadAssetAtPath(assetPath, typeof(ScriptableObject)) as ScriptableObject;
  • 1
  • 2
  • 3

警告:測試

Invalid AssetDatabase path: E:/MyTest/Assets/aaaaa.asset. Use path relative to the project folder.this

  • 經過AssetBundle加載使用,假定已經拿到了AssetBundle資源res的狀況下: 
    AssetBundle res;
ScriptableObject obj = res.LoadAllAssets()[0] as ScriptableObject; //TODO取用obj繼續操做 
  • 1
  • 2

可是這麼寫也有不保險的時候,由於在Unity中 .asset 和 ScriptableObject 類是兩個獨立的文件,萬一我拿到的是「髒AB」,拿到了非空的AssetBundle,但裏面關聯的ScriptableObject已經被刪除或丟失了怎麼辦?這個時候還要判斷該AB 的有效性: 
簡單的作法是spa

if (res.LoadAllAssets().Length == 0) { //TODO res中ScriptableObject引用丟失,該資源異常 }
  • 1
  • 2
  • 3
  • 4

不然若是不判斷的話,即便拿到了AB也無法繼續有效的處理,Unity仍是會拋出警告的3d

最後:附上我在GitHub上傳的簡單序列化對象的用法,約定了序列化對象的定義,建立及加載。:) 
點擊這裏

相關文章
相關標籤/搜索