ScriptableObject 对象化的运用
http://www.cnblogs.com/oldman/articles/2409554.html
using UnityEngine;
using UnityEditor;
using System.IO; public static class CustomAssetUtility
{
public static void CreateAsset<T> () where T : ScriptableObject
{
T asset = ScriptableObject.CreateInstance<T> (); string path = AssetDatabase.GetAssetPath (Selection.activeObject);
if (path == "")
{
path = "Assets";
}
else if (Path.GetExtension (path) != "")
{
path = path.Replace (Path.GetFileName (AssetDatabase.GetAssetPath (Selection.activeObject)), "");
} string assetPathAndName = AssetDatabase.GenerateUniqueAssetPath (path + "/New " + typeof(T).ToString() + ".asset"); AssetDatabase.CreateAsset (asset, assetPathAndName); AssetDatabase.SaveAssets ();
EditorUtility.FocusProjectWindow ();
Selection.activeObject = asset;
}
}
ScriptableObject 是Unity3D整个引擎的设计中,最为出彩的地方。通过他我们将数据保存,数据和编辑器的交互以及数据在runtime的使用三部分很方便的联系在一起。这是一个容易被Unity3D的初学者们容易忽略的领域。
简单的说,你可以把ScriptableObject当作Unity3D下的xml。但是其存储格式为二进制。让我们从一个实际例子出发,来理解ScriptableObject在实际项目中的整个运用。
假设我们有AbilityInfo需要设置和保存,我们可以将AbilityInfo制作成ScriptableObject,如下:
public class AbilityInfo : ScriptableObject {
public enum Type {
Unknown,
FireBall,
FireWall,
IceBall,
DarkForce,
Heal,
Poison,
}
public Type type = Type.Unknown;
public float point = 10.0f;
public float affectRange = 100.0f;
}
创建ScriptableObject
ScriptableObject 可以通过 ScriptableObject.CreateInstance<T>() 动态创建。然而将它保存为Unity3D Asset是ScriptableObject的设计本意。一般的,我们通过这个函数来完成整个创建过程:
public static class AbilityInfoUtility {
public static AbilityInfo Create ( string _path, string _name ) {
//
if ( new DirectoryInfo(_path).Exists == false ) {
Debug.LogError ( "can't create asset, path not found" );
return null;
}
if ( string.IsNullOrEmpty(_name) ) {
Debug.LogError ( "can't create asset, the name is empty" );
return null;
}
string assetPath = Path.Combine( _path, _name + ".asset" );
//
AbilityInfo newAbilityInfo = ScriptableObject.CreateInstance<AbilityInfo>();
AssetDatabase.CreateAsset(newAbilityInfo, assetPath);
Selection.activeObject = newAbilityInfo;
return newAbilityInfo;
}
}
注意1: 这是一个在Editor下使用的函数,所以这份代码需要放在项目中名为 “Editor” 的文件夹中 (目录层次无所谓),并且需要在代码开头处引入: using UnityEditor;
注意2: ScriptableObject的脚本文件名必须和他的类名一致,并且一个脚本文件只能对应一个ScriptableObject定义。
注意3: ScriptableObject只能保存为后缀名为”.asset”的文件,其他格式Unity3D将不能正确读取。
将Asset的创建方式提供给用户
对于编辑器的使用者,自然需要有UI或者方便的执行脚本方法来帮助创建数据。我们使用[MenuItem]来完成操作。以下代码会将Asset的创建加入到Project Window的右键菜单中:
class AbilityInfoUtility {
...
[MenuItem ("Assets/Create/Ability Info")]
static void Create () {
// get current selected directory
string assetName = "New AbilityInfo";
string assetPath = "Assets";
if ( Selection.activeObject ) {
assetPath = AssetDatabase.GetAssetPath(Selection.activeObject);
if ( Path.GetExtension(assetPath) != "" ) {
assetPath = Path.GetDirectoryName(assetPath);
}
}
//
bool doCreate = true;
string path = Path.Combine( assetPath, assetName + ".asset" );
FileInfo fileInfo = new FileInfo(path);
if ( fileInfo.Exists ) {
doCreate = EditorUtility.DisplayDialog( assetName + " already exists.",
"Do you want to overwrite the old one?",
"Yes", "No" );
}
if ( doCreate ) {
AbilityInfo abilityInfo = AbilityInfoUtility.Create ( assetPath, assetName );
Selection.activeObject = abilityInfo;
// EditorGUIUtility.PingObject(border);
}
}
}

自定义编辑显示
ScriptableObject 可以通过自定义编辑器的方式进行特殊编辑。编辑器方面有EditorWindow和Editor两种方式。EditorWindow更多地用在一些复杂数 据的可视化编辑。对于一些小的行为改变,我们可以通过Editor来实现。本节我们也已介绍Editor的编辑为主。设我们需要为AbilityInfo 在Inspector中加入预览图标。我们先于提供预览图标的美术工作人员约定好图标的存放位置和名称,如Editor/Icons/Ability 目录内。这里我们通过简单的硬编码来存取这些图标 (更灵活的做法是提供一些辅助的设置gui等)。我们在AbilityInfoUtility中添加如下函数:
public static class AbilityInfoUtility {
...
public static Texture2D GetTextureByType ( AbilityInfo.Type _type ) {
switch ( _type ) {
case AbilityInfo.Type.Unknown:
return AssetDatabase.LoadAssetAtPath ( "Assets/Editor/Icons/Ability/Unknown.png", typeof(Texture2D) ) as Texture2D;
case AbilityInfo.Type.FireBall:
return AssetDatabase.LoadAssetAtPath ( "Assets/Editor/Icons/Ability/FireBall.png", typeof(Texture2D) ) as Texture2D;
case AbilityInfo.Type.FireWall:
return AssetDatabase.LoadAssetAtPath ( "Assets/Editor/Icons/Ability/FireWall.png", typeof(Texture2D) ) as Texture2D;
case AbilityInfo.Type.IceBall:
return AssetDatabase.LoadAssetAtPath ( "Assets/Editor/Icons/Ability/IceBall.png", typeof(Texture2D) ) as Texture2D;
case AbilityInfo.Type.DarkForce:
return AssetDatabase.LoadAssetAtPath ( "Assets/Editor/Icons/Ability/DarkForce.png", typeof(Texture2D) ) as Texture2D;
case AbilityInfo.Type.Heal:
return AssetDatabase.LoadAssetAtPath ( "Assets/Editor/Icons/Ability/Heal.png", typeof(Texture2D) ) as Texture2D;
case AbilityInfo.Type.Poison:
return AssetDatabase.LoadAssetAtPath ( "Assets/Editor/Icons/Ability/Poison.png", typeof(Texture2D) ) as Texture2D;
}
return null;
}
}
要自定义Inspector显示,只需要通过在派生的Editor中标记上[CustomEditor(Type)]这个Attribute即可,这里给出一个简单的示例:
[CustomEditor(typeof(AbilityInfo))]
public class AbilityInfoEditor : Editor {
public override void OnInspectorGUI () {
AbilityInfo editInfo = target as AbilityInfo;
GUI.DrawTexture ( new Rect( 20, 20, 40, 40 ), AbilityInfoUtility.GetTextureByType(editInfo.type) );
GUILayoutUtility.GetRect ( 40, 40 );
GUILayout.Space (5);
base.OnInspectorGUI();
}
}
注意: 这里的base.OnInspectorGUI()实际上是比较偷懒的做法。对于需要仔细定义每个属性用途和显示的数据,请参考Unity3D的EditorGUI, EditorGUILayout文档认真编写。

在MonoBehavior中引用数据
现在我们只需要在MonoBehavior中引用这份数据,在读取场景的时候,就会自动帮助我们完成数据的序列化操作。
public class MyBehavior : MonoBehavior {
public AbilityInfo normalSkill1;
public AbilityInfo normalSkill2;
public AbilityInfo specialSkill;
}
ScriptableObject 对象化的运用的更多相关文章
- ScriptableObject本地序列化后重启Unity后报The associated script can not be loaded.Please fix any compile errors and assign a valid script的坑
踩坑 做编辑器一些设置序列化存在本地的时候,继承自ScriptableObject的类通过 创建的asset文件. 在重启Unity后查看这个asset发现上面的所有序列化属性丢失,报的错就是 在不存 ...
- unity, 由scriptableObject创建.asset
由继承自scriptableObject的类X创建.asset文件. 假设类X的定义为: [System.Serializable] public class X : ScriptableObject ...
- [cb]ScriptableObject 序列化
ScriptableObject ScriptableObject是一个类,它允许你存储大量用于共享的数据独立脚本实例,不要迷惑这个类同样可以叫做 SerializableObject,可以理解成是一 ...
- Unity ScriptableObject的使用
ScriptableObject主要实现对象序列化的保存,因为是Unity自己的序列化,所以比xml,json序列化方便很多,但相对可控性也比较差 1.Editor下写入和读取测试: using Un ...
- EditorWindow edit ScriptableObject
using UnityEngine; [System.Serializable] public class Weapon { //[SerializeField] public string weap ...
- Unity3D之ScriptableObject学习笔记
不同与C#提供的Serializable序列化功能,ScriptableObject是Unity3D提供的一个数据存储类,我们接下来学习一下这个类的功能. 官方文档 http://docs.unity ...
- C语言对象化编程
以下为一个引子: C中struct的函数实现,只能用函数指针成员. C结构体内不能有函数的代码,但可以有函数的指针. C/C code Code highlighting produced by Ac ...
- 用DELPHI的RTTI实现数据集的简单对象化
在<强大的DELPHI RTTI--兼谈需要了解多种开发语言>一文中,我说了一下我用DELPHI的RTTI实现了数据集的简单对象化.本文将详细介绍一下我的实现方法. 首先从一个简单 ...
- 自定义ScriptableObject属性显示
自定义ScriptableObject属性显示的三种方式 1. 继承Editor,重写OnInspectorGUI方法 Editor官方文档 需求 将TestClass中intData属性和strin ...
随机推荐
- Hibernate 对象的生命周期及CRUD操作
对象状态及生命周期 1.Transient(瞬时状态):new的对象为瞬时态 session中没有数据,数据库中没有数据. 2.Persistent(持久状态):被session管理的对象为持久状态, ...
- Codeforces 622 F. The Sum of the k-th Powers
\(>Codeforces \space 622\ F. The\ Sum\ of\ the\ k-th\ Powers<\) 题目大意 : 给出 \(n, k\),求 \(\sum_{i ...
- luoguP3750 [六省联考2017]分手是祝愿 概率期望DP + 贪心
...........真的神状态了,没办法去想的状态................... 考试的时候选择$50$分贪心+$15$分状压吧,别的点就放弃算了........ 令$f[i]$表示从最小步 ...
- 对Java Serializable(序列化)的理解和总结(二)
遇到这个 Java Serializable 序列化这个接口,我们可能会有如下的问题a,什么叫序列化和反序列化 b,作用.为啥要实现这个 Serializable 接口,也就是为啥要序列化 c,ser ...
- 某DP题目1
题意: 有n个由左右括号组成的字符串,选择其中若干字符串,使得组成的括号序列合法且长度最长.n <= 1000,n个字符串的长度和 <= 10000. 分析: 其实我一开始做这一题的时候, ...
- 四、python之 if while for
一.if条件判断 if 条件判断: 逻辑操作…… …… else: 逻辑操作…… 其中"判断条件"成立时(非零),则执行后面的语句,而执行内容可以多行,以缩进来区分表示同一范围. ...
- uoj 41 【清华集训2014】矩阵变换 婚姻稳定问题
[清华集训2014]矩阵变换 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://uoj.ac/problem/41 Description 给出 ...
- 博雅PHP高级工程师面试题-自拟
作者:元如枫 2010年 1.现有学校课程内容系统简单需求描述,试着提供解决方案. 需求简单描述如下: 1)对象及属性 学校: 学校名称,学校所属分类,学校介绍,学校地图标记,学校所属地区,标签, ...
- java内存泄露补充样例
前几天写了个内存泄露的文章.里面介绍了内存泄露的相关知识:http://blog.csdn.net/u010590685/article/details/46973735 但是里面给的样例不是非常好, ...
- 【mybatis】mysql级联更新两个表或多张表的数据
例如 info表和relation表有关联,现在要在一个sql语句中同时级联更新两张表的数据 update security_code_info info LEFT JOIN security_cod ...