关于ScriptableObject的使用
前言:
这两天在看Attribute章节时,看到了CreateAssetMenuAttribute,通过Asset/Create的子弹菜单,来快捷的创建ScriptableObject
派生类的实例,并以.aaset资源文件的形式,保存在项目中。
这是个蛮不错的设计,官方文档解释称,如果你想要创建一些对象,而这些对象并不依赖GameObject,不使用GetComponent
之类的方法,你可以从ScriptableObject类派生,该类继承自Object.源码如下:
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using UnityEngine.Scripting;
namespace UnityEngine
{
[RequiredByNativeCode]
[StructLayout (LayoutKind.Sequential)]
public class ScriptableObject : Object
{
//
// Constructors
//
public ScriptableObject ();
//
// Static Methods
//
[GeneratedByOldBindingsGenerator]
[MethodImpl (MethodImplOptions.InternalCall)]
public static extern ScriptableObject CreateInstance (string className);
public static ScriptableObject CreateInstance (Type type);
public static T CreateInstance<T> () where T : ScriptableObject;
[GeneratedByOldBindingsGenerator]
[MethodImpl (MethodImplOptions.InternalCall)]
private static extern ScriptableObject CreateInstanceFromType (Type type);
[GeneratedByOldBindingsGenerator]
[MethodImpl (MethodImplOptions.InternalCall)]
private static extern void INTERNAL_CALL_SetDirty (ScriptableObject self);
[GeneratedByOldBindingsGenerator, ThreadAndSerializationSafe]
[MethodImpl (MethodImplOptions.InternalCall)]
private static extern void Internal_CreateScriptableObject ([Writable] ScriptableObject self);
//
// Methods
//
[Obsolete ("Use EditorUtility.SetDirty instead")]
public void SetDirty ();
}
}
派生自ScriptableObject的类:
public class testEdit : ScriptableObject {
public int a = 10;
public int b = 11;
public int c = 12;
[Multiline][ContextMenuItem("Reset", "ResetString")]
public string abc;
}
创建实例有两种形式:
1.通过代码来创建实例,并完成初始化,最后存储到本地,后缀为".asset"。
testEdit test = testEdit.CreateInstance<testEdit> ();
test.name = "testEdit";
test.a = 5;
test.b = 6;
test.c = 7;
test.abc =""+test.a + test.b + test.c;
UnityEditor.AssetDatabase.CreateAsset (test, "Assets/"+test.name+".asset");
2.通过添加CreateAssetMenuAttribute,在Assets/Create上进行快捷创建。
[CreateAssetMenu(fileName = "xxxx",menuName = "xxx/xxx")]
public class testEdit : ScriptableObject {
public int a = 10;
public int b = 11;
public int c = 12;
[Multiline][ContextMenuItem("Reset", "ResetString")]
public string abc;
}
说明:
fileName:生成asset文件的文件名。
menuName:在Assets/Create上子菜单的名字。
创建后的资源文件可以直接图形化的设计对象参数的值。并保存。通过成后的testEdit.asset,可以设置assetbudleName来
成assetBundle。
查看生成后的testEdit.asset文件:
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 49f3c284ec29c234a86002519acaf09e, type: 3}
m_Name: testEdit
m_EditorClassIdentifier:
a: 5
b: 6
c: 7
abc: 567
使用的YAML非标记语言将类的信息存储起来,并不是我们序列化生成的字节流。
读取testEdit.asset,如果你设置成了AssetBundle,直接使用AssetBundle的方式加载即可,否则就放在Resources文件夹下,如下:
testEdit t = (testEdit)Resources.Load ("testEdit");
if (t != null) {
Debug.Log (t.a + "," + t.b + "," + t.c + "," + t.abc);
}
最后,ScriptableObject派生的类可以方便的存储成外部文件,并且以图形化的操作修改对象的属性数值。
比如一些静态的数据,如常量,关卡,任务,成就等等配置表,与将类序列化成字节流文件并运行时反序列化转换成对象的使用流程是一样的。
但如果说是用来做静态数据表,显然这是没有EXCEL里操作更为方便,非技术人员通常都喜欢用EXCEL来操作配置表,更灵活,功能更强大,自由度更高,且更方便使用,技术只要提供导出工具,不论是导出外部的数据文件,xml,json,pb,自定义等等,还是在导出的过程中,直接序列化成文件都可以,而且这些通常都有了比较成熟的解决方案,在unity引擎之前很多都是这么过来的。
我目前在项目中还没有使用过ScriptableObject的地方,有些功能确实是可以使用他来实现,但是已经有其它的解决办法了,本质上并没有什么区别。
更新(2018.7.25):听腾讯一位前端大拿说,不太推荐使用ScriptableObject,因为他的解析效率比较低,不及pb以及Json,但在开发编辑器时,可以把编辑器所需要的一些数据存下来,使用这种形式还是可以的。
到此为止,如果大家发现有什么不对的地方,欢迎指正,共同提高,感谢您的阅读!
编辑于2018.7.19
时间过得好快,世界杯已经过去4天了,中超也随之开始,保利尼奥刚踢完世界杯就回到了中超,真是明智之举,他很难再进入下一次世界杯大名单,巴萨在下赛季也不一定有他的位置,他在巴萨这一年的表现还是很惊艳的,又拿到了联赛冠军和国王杯,非常的让人羡慕,但那毕竟是巴萨,竟争力太强,自己也快到了足球生涯的末期,恒大能给出一笔非常有诚意的合同,
这是一定要仔细考虑的,我相信他的选择是无比正确的,他在恒大踢出了成绩,去了巴萨,实现了自己的梦想,现在回到恒大
继续效力直至职业生涯终老,没有什么比这更好的结局了。祝福保利尼奥,希望拿下恒大八连冠!