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上传的简单序列化对象的用法,约定了序列化对象的定义,建立及加载。:) 
点击这里

相关文章
相关标签/搜索