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 ...
随机推荐
- vmware12安装centos7系统详解
1.首先需要准备的工具有vmware12和contos7的系统. vmvare12下载地址: http://pan.baidu.com/s/1i5vH50D contos7我自己使用的为1511版本. ...
- CodeForces 602C The Two Routes(最短路)
Description In Absurdistan, there are n towns (numbered 1 through n) and m bidirectional railways. T ...
- 快速排序-C
#include <stdio.h> #include <stdlib.h> #define N 6 int partition(int arr[], int low, int ...
- [TC6194]AllWoundUp
[TC6194]AllWoundUp 题目大意: 有\(A\)和\(B\)两个人.\(A\)在平面上游走,\(B\)会一直盯着\(A\)看,站在\(x\)轴某个位置上不动,并随着\(A\)的运动旋转身 ...
- Java并发(九):重入锁 ReentrantLock
先做总结: 1.为什么要用ReentrantLock? (1)ReentrantLock与synchronized具有相同的功能和内存语义: (2)synchronized是重量级锁,性能不好.Ree ...
- keystone 命令简要说明
catalog: keystone catalog 可以显示所有已有的service keystone catalog --service service-type 显示某个service信息 end ...
- Ext文本输入框:Ext.form.TextField属性汇总(转) (
本章介绍Ext.form.TextField组件的基本用法: <form id="form1" runat="server"> <div ...
- Scrapy 轻松定制网络爬虫(转)
网络爬虫(Web Crawler, Spider)就是一个在网络上乱爬的机器人.当然它通常并不是一个实体的机器人,因为网络本身也是虚拟的东西,所以这个“机器人”其实也就是一段程序,并且它也不是乱爬,而 ...
- WinDbg-如何抓取dump文件
这要分两种情况:第一种情况:如果是Vista或者是Windows2008操作系统就是一个简单的事情,在任务管理器中,切换到"进程"选项卡,右键点击你想要创建dump文件的进程,然后 ...
- HDU 4685 Prince and Princess (2013多校8 1010题 二分匹配+强连通)
Prince and Princess Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Othe ...