zoukankan      html  css  js  c++  java
  • ScriptableObject

    什么是ScriptableObject?

    点击查看Unity官网的描述

    直译过来就是“脚本化对象”,换言之这类作为存储结构化的数据来使用,并写入Unity的资源.asset文件去存储一组数据,取用的时候直接作为一个数据对象拿来用,很方便。

    ScriptableObject 有什么好处?

    • Unity用于创建不需要绑定到物体的对象,即非继承于Mono,该类继承于UnityEngine.Object
    • 存放编辑器或数据配置文件
    • 方便操作管理,可以可视化编辑
    • 取数据方便,ScriptableObject已经是可序列化的数据,不用像读取纯文本或xml那样还要繁琐耗时的数据解析过程

    不过根据近期使用发现它也有一些不足

    • 虽然编辑可视化,但受限于数据量,存放的数据太多的时候,阅读就不直观了,如图数据多了想编辑需要一项项展开,查找也不方便, 
      image 
      这里写图片描述

    针对ScriptableObject的内容多时编辑不直观的情况,最好是数据源头管理出发修编辑修改数据,如数据来源于管理器创建、.txt、数据库、Excel表等等,最好直接去修改原数据。 我尝试了写一个GUI数据编辑器,结果就是更恶心更不直观。

    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.

    • 通过AssetBundle加载使用,假定已经拿到了AssetBundle资源res的情况下: 
      AssetBundle res;
    ScriptableObject obj = res.LoadAllAssets()[0] as ScriptableObject;
    //TODO取用obj继续操作 
    • 1
    • 2

    但是这么写也有不保险的时候,因为在Unity中 .asset 和 ScriptableObject 类是两个独立的文件,万一我拿到的是“脏AB”,拿到了非空的AssetBundle,但里面关联的ScriptableObject已经被删除或丢失了怎么办?这个时候还要判断该AB 的有效性: 
    简单的做法是

    if (res.LoadAllAssets().Length == 0)
    {
       //TODO res中ScriptableObject引用丢失,该资源异常
    }
    • 1
    • 2
    • 3
    • 4

    否则如果不判断的话,即使拿到了AB也没法继续有效的处理,Unity还是会抛出警告的

    最后:附上我在GitHub上传的简单序列化对象的用法,约定了序列化对象的定义,创建及加载。:) 
    点击这里

  • 相关阅读:
    deferred 对象
    JVM--------3
    JVM类加载机制————2
    JVM加载的初始化类
    补充==的使用和equals的区别
    MyBatis_SelectKey使用oracle 序列插入主键
    MySql_ procedure
    mysql function
    jsonp _____跨域请求实现
    shell(shell变量、条件表达式、流程控制)
  • 原文地址:https://www.cnblogs.com/nafio/p/9593107.html
Copyright © 2011-2022 走看看