[cb]ScriptableObject 序列化
ScriptableObject
ScriptableObject是一个类,它允许你存储大量用于共享的数据独立脚本实例,不要迷惑这个类同样可以叫做 SerializableObject,可以理解成是一个Unity串行化工具。这是一个编辑器类并且你可以在Inspector面板中编辑数据。例如:如果你有一个存储了一百万数据的 int[],这个数组占用4MB内存,放在Prefab上,那么当你每次实例化Prefab,你都会得到这个数组的一个副本。如果你实例化10个这个Prefab,那就会占用40MB内存。
可序列化的类型
Unity的serializes(序列化)支持所有原生的类型,也支持strings,arrays,lists还有Unity的Vector3等都支持,而且还支持自定义的类,但需要有一个串行的属性。
使用情景
预期使用情况,使用ScriptableObject是减少内存使用量,避免Values的副本。但是你也可以用它来定义可插拨的数据集。这方面的一个例子是:想像RPG游戏中的NPC商店,你可以创建自定义ShopContens ScriptableObject,每个资产定义了一组可用于购买物品。在这样一个场景,游戏中有三个区域,每个区域都可以提供不同层级的项目。你的店铺脚本将引用ShopContents对象,定义哪些项目可供选择。
Tips
当在检查ScriptableObject引用时,你可以在Inspector双击这个参考字段。
你可以创建一个自定义的Editor来查看不同的类似在Inspector,以帮助你管理它所表示的数据。
游戏关卡数据序列化
策划需求
一个游戏中的配置表数据,这些数据一般都是由策划在Excel等工具上配置,要运用到游戏中时,一般需要做一个转换,比如类似转换。这时可以使用ScriptableObject,将数据预先处理成程序需要访问的数据结构,存储在ScriptableObject中,然后打包成一个外部文件,这样在游戏运行的时候就不用做解析和组装了,这个功能对大批量的公用数据尤其有用!!
思路分析
策划在Art工程拼接好关卡信息之后,客户端根据关卡的中元素的位置,大小等信息生成出关卡,这中间有一个存储关卡信息的过程。我们的做法是把关卡的信息存储在ScriptableObject上,然后在Editor里,把当前关卡信息存储在Product目录下做为一个文件。Client直接读取这个MapObject文件
MapSetting.cs
using UnityEngine;
using System.Collections;
using System.Collections.Generic; //地图信息打包成外部文件,供Client读取
public class CMapSetting : ScriptableObject
{
public List<string> TexturesDependencies;//依赖的贴图
public string MapObjectPath;//MapRoot public List<CLevelBattleSetting> Battles;//战役信息
}
导出关卡数据代码
public void ExportCurrentScene()
{
SceneName = EditorApplication.currentScene.Substring(EditorApplication.currentScene.LastIndexOf('/') + 1);
SceneName = SceneName.Substring(0, SceneName.LastIndexOf('.'));
string exportPath = string.Format("Scene/{0}{1}", SceneName, GameDef.ASSET_BUNDLE_FILE_EXT); string mapObjectPath = string.Format("Scene/{0}_MapObject{1}", SceneName, GameDef.ASSET_BUNDLE_FILE_EXT); CSimBattle[] battles = GameObject.FindObjectsOfType<CSimBattle>();//获取所有的Battle List<CSimBattle> battleList = new List<CSimBattle>(battles);
battleList.Sort((CSimBattle x, CSimBattle y) =>
{
return x.transform.position.y.CompareTo(y.transform.position.y);
});//根据Battle的Y进行排序 CSimActor[] actors = GameObject.FindObjectsOfType<CSimActor>();//获取所有的Actor
List<CSimActor> actorList = new List<CSimActor>(actors);
int count = 0;//测试一个Battle中多少只怪
List<CLevelBattleSetting> LevelBattleSettings = new List<CLevelBattleSetting>();//有多少关卡 for (int b = 0; b < battleList.Count; b++)//遍历Battle
{
CSimBattle simBattle = battleList[b];
CLevelBattleSetting levelBatSetting = new CLevelBattleSetting();//创建一个新的BattleSetting实例
levelBatSetting.MapActorSettings = new List<CMapActorSetting>();//Battle中的Actor设置信息
levelBatSetting.Num = simBattle.KillNum;
levelBatSetting.Time = simBattle.BattleTime;
levelBatSetting.StoryOnStart = simBattle.StoryOnStart;
levelBatSetting.StoryOnEnd = simBattle.StoryOnEnd;
levelBatSetting.CurPosition = simBattle.transform.position;
//CBase.Log("CSimBattle.CurPosition:{0}", levelBatSetting.CurPosition); float battlePosY = simBattle.transform.position.y;//Battle的Y值
for (int a = (actorList.Count - 1); a >= 0; a--)//遍历怪
{
float actorPosY = actorList[a].transform.position.y;//Actor的Y值
if (actorPosY <= battlePosY)//判断这个Actor是否在这个Battle内
{
CMapActorSetting actorSetting = new CMapActorSetting();
CSimActor simActor = actorList[a];
actorSetting.NpcId = simActor.NPC编号;
actorSetting.NpcLevel = simActor.NPC等级;
actorSetting.NpcPosition = simActor.transform.position;
actorSetting.IsEnemy = simActor.是否敌人; levelBatSetting.MapActorSettings.Add(actorSetting);//把怪添加到关卡中
actorList.Remove(simActor);//移除已经添加的Actor
count += 1;
}
} LevelBattleSettings.Add(levelBatSetting);//把battle添加进关卡地图中
CBase.Log("Battle :{0} 有怪物 {1} 只" ,b, count);//打印一个Battle中有多少怪
count = 0;
}
//CBase.Log("当前关卡共有 {1} 个Battle", LevelBattleSettings.Count); GameObject mapRoot = GameObject.Find("MapRoot");
if (mapRoot != null)
{
List<string> textureList = new List<string>();//存放打包好图片的路径
Renderer[] renderers = mapRoot.GetComponentsInChildren<Renderer>();
foreach (Renderer child in renderers)
{
Texture _texture = child.sharedMaterial.mainTexture;
string _path = AssetDatabase.GetAssetPath(_texture);
_path = XBuildTools.GetUniquepath(_path);
if (!textureList.Contains(_path))
{
textureList.Add(_path);
XBuildTools.PushAssetBundle(_texture, string.Format("Textures/{0}{1}", _path, GameDef.ASSET_BUNDLE_FILE_EXT));
CBase.Log("Texture导出成功! =>{0}", _path);
}
} XBuildTools.PushAssetBundle(mapRoot, mapObjectPath);//打包 mapRoot
Debug.Log("地图导出成功!" + SceneName);
XBuildTools.PopAssetBundle();
//XBuildTools.PopAllAssetBundle(); CMapSetting mapSetting = ScriptableObject.CreateInstance<CMapSetting>();
mapSetting.TexturesDependencies = textureList;
mapSetting.MapObjectPath = mapObjectPath;
mapSetting.Battles = LevelBattleSettings;
XBuildTools.BuildScriptableObject(mapSetting, exportPath);//序列化 MapSetting的位置啊,路径信息。
}
}
打包出的关卡文件
文档资料
Unity Manual:http://docs.unity3d.com/Manual/class-ScriptableObject.html
Scripting API:http://docs.unity3d.com/ScriptReference/ScriptableObject.html
[cb]ScriptableObject 序列化的更多相关文章
- SerializeField和Serializable
Serialize功能 Unity3D 中提供了非常方便的功能可以帮助用户将 成员变量 在Inspector中显示,并且定义Serialize关系. 简单的说,在没有自定义Inspector的情况下所 ...
- Unity编辑器环境在Inspector面板中显示变量
Serialize功能Unity3D 中提供了非常方便的功能可以帮助用户将 成员变量 在Inspector中显示,并且定义Serialize关系. 简单的说,在没有自定义Inspector的情况下所有 ...
- Unity插件 - MeshEditor(五) 网格顶点动画(变形动画)
源码已上传至github,并持续更新,链接请看底部.(本帖跟随github持续更新) 网格顶点动画(变形动画)是针对于物体的形状可以随意变换并记录为关键帧的动画,虽然模型的顶点数据还是应该交给GPU绘 ...
- ScriptableObject本地序列化后重启Unity后报The associated script can not be loaded.Please fix any compile errors and assign a valid script的坑
踩坑 做编辑器一些设置序列化存在本地的时候,继承自ScriptableObject的类通过 创建的asset文件. 在重启Unity后查看这个asset发现上面的所有序列化属性丢失,报的错就是 在不存 ...
- 玩转Unity资源,对象和序列化(上)
这是一系列文章中的第二章,覆盖了Unity5的Assets,Resources和资源管理 本文将从Unity编辑器和运行时两个角度出发,主要探讨以下两方面内容:Unity序列化系统内部细节以及Unit ...
- Unity ScriptableObject的使用
ScriptableObject主要实现对象序列化的保存,因为是Unity自己的序列化,所以比xml,json序列化方便很多,但相对可控性也比较差 1.Editor下写入和读取测试: using Un ...
- Java对象的序列化(Object Serialization)
先定义两个简单的类: package comm; import java.io.Serializable; import java.util.Date; import java.util.Gregor ...
- Unity3D之ScriptableObject学习笔记
不同与C#提供的Serializable序列化功能,ScriptableObject是Unity3D提供的一个数据存储类,我们接下来学习一下这个类的功能. 官方文档 http://docs.unity ...
- Java序列化的机制和原理
Java序列化的机制和原理 本文讲解了Java序列化的机制和原理.从文中你可以了解如何序列化一个对象,什么时候需要序列化以及Java序列化的算法. 有关Java对象的序列化和反序列化也算是Java基础 ...
随机推荐
- Incorrect string value: '\xF0\x90\x8D\x83...' for column 通用解决方案
mysql插入非ascii字符时报这个错的根本原因在于: 对应表的字符集无法存储要插入的字符,比如汉字插入latin1编码,某些特殊字符插入gbk或者utf8等. 检查一下实际插入的字符以及对应表或者 ...
- Android应用开发基础之九:内容提供者(ContentProvider)
内容提供者 应用的数据库是不允许其他应用访问的 内容提供者的作用:就是让别的应用访问到你的数据库 自定义内容提供者,继承ContentProvider类,重写增删改查方法,在方法中写增删改查数据库的代 ...
- HTML · 图片热点,网页划区,拼接,表单
图片热点: 规划出图片上的一个区域,可以做出超链接,直接点击图片区域就可以完成跳转的效果. 网页划区: 在一个网页里,规划出一个区域用来展示另一个网页的内容. 网页的拼接: 在一个网络页面内,规划出多 ...
- 【GOF23设计模式】建造者模式
来源:http://www.bjsxt.com/ 一.[GOF23设计模式]建造者模式详解类图关系 建造飞船 package com.test.Builder; public class AirShi ...
- [Xamarin.iOS] Visual Studio中Xamarin.iOS项目,无法加入PCL项目参考、NuGet组件参考
[Xamarin.iOS] Visual Studio中Xamarin.iOS项目,无法加入PCL项目参考.NuGet组件参考 解决方案 目前Visual Studio中最新版本的Xamarin.iO ...
- ABAP中正则表达式的简单使用方法 (转老白BLOG)
在一个论坛上面看到有人在问正则表达式的问题,特举例简单说明一下.另外,REPLACE也支持REGEX关键字.最后:只能是ECC6或者更高版本才可以(ABAP supports POSIX regula ...
- Java中字节流和字符流的比较(转)
字节流与和字符流的使用非常相似,两者除了操作代码上的不同之外,是否还有其他的不同呢? 实际上字节流在操作时本身不会用到缓冲区(内存),是文件本身直接操作的,而字符流在操作时使用了缓冲区,通过缓冲区再操 ...
- 转:HTTP 1.1与HTTP 1.0的比较
原文地址:http://blog.csdn.net/elifefly/article/details/3964766 HTTP 1.1与HTTP 1.0的比较 一个WEB站点每天可能要接收到上百万的用 ...
- Windows环境下利用github快速配置git环境
在windows环境下利用github客户端我们可以直接拥有可视化的界面来管理工程,当然你也可以选择你喜欢的命令行工具来做.今天我分享一个比较快速的方式来配置git环境. 先去下载github的win ...
- android ButterKnife 解决重复findViewById
简介: 程序员都是懒惰的,不想写一大堆像下面这样的代码 class ExampleActivity extends Activity { TextView title; TextView subtit ...