Unity的c json 序列化问题配表问题用什么方法比较好

程序写累了,就来玩玩酷跑小游戏吧,嘿嘿。
雨松MOMO送你一首歌曲,嘿嘿。
Unity3D研究院编辑器之序列化的对象修改格式(十九)
Unity3D研究院编辑器之序列化的对象修改格式(十九)
围观18663次
编辑日期: 字体:
一般在做编辑器的时候会给策划做一些脚本或者ScriptableObject,让策划进行或拽赋值等操作。举个例子假如开始策划说我只需要拖放一个GameObject,但是N天以后策划说这里想拖多个GameObject. 那么如果开始序列化的数据不是List&GameObject&那么就悲剧了,数据结构一变策划之前拖拽过的工作都玩白做了。。有些人为了做兼容不得不在写一个新的数据结构让策划来填写,但是这样就得是多个变量了,代码看起来比较丑了。
其实Unity也意识到这个问题了。他们提供了一个方案
FormerlySerializedAs(name)
public string a1; [FormerlySerializedAs("a1")] public string a2;
这样可以把a1删除了,然后 a1序列化的数据就保存在a2里。但是它这个有局限性,比如这里我想把a1的数据放到一个新的对象里就不行了。比如这样
12345678910111213
public class NewBehaviourScript : MonoBehaviour {& public Hero hero;&}&&[System.Serializable]public class Hero{ [FormerlySerializedAs("a1")] public string a2;}
而且它这个只能替换相同数据结构,假如我想GameObject放到List&GameObject&里也不行了。。。所以我写了一个批量赋值的工具。把MonoBehaviour和ScriptableObject以泛型的形式传进去,让旧的数据等于新的数据、然后在类里把就把旧的变量直接删除掉就好了。
12345678910111213141516171819202122232425262728293031323334353637383940
using UnityEngine;using System.Collections;using UnityEditor;using System.Collections.Generic;&public class TestEditor : Editor {&& [MenuItem("1/ModifyPrefab")] static void Test() {
ModifyAsset.ModifyPrefab&NewBehaviourScript&(delegate(Component obj) {
NewBehaviourScript&&script = obj as NewBehaviourScript;
script.hero.objects = new List&GameObject&(){script.obj};
}); }&&& [MenuItem("1/ModifyScene")] static void Test1() {
ModifyAsset.ModifyScene&NewBehaviourScript&(delegate(Component obj){
NewBehaviourScript&&script = obj as NewBehaviourScript;
script.hero.objects = new List&GameObject&(){script.obj};
}); }& [MenuItem("1/ModifyScriptableObject")] static void Test2() {
ModifyAsset.ModifyScriptableObject&MyAsset&(delegate(ScriptableObject obj) {
MyAsset&&script = obj as MyAsset;
script.hero.objects = new List&GameObject&(){script.obj}; &
可能出现这个问题的只有三处
1.prefab里的数据
2.scene里的数据
3.ScriptableObject
核心代码就是遍历、找到以后回调出去。
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
#if UNITY_EDITORusing UnityEngine;using System.Collections;using System.Collections.Generic;using UnityEditor;using UnityEngine.SceneManagement;using System.Reflection;using System;using UnityEditor.SceneManagement;public class ModifyAsset{ static public void ModifyPrefab&T& (Action&Component&callBack) where T: MonoBehaviour {
string[] guids = AssetDatabase.FindAssets ("t:Prefab");&
foreach (string guid in guids) {
string path = AssetDatabase.GUIDToAssetPath (guid);
GameObject obj = AssetDatabase.LoadAssetAtPath&GameObject& (path);
T[] scripts = obj.GetComponentsInChildren&T& (true);&
for (int i = 0; i & scripts.Length; i++)
callBack (scripts[i]);
EditorUtility.SetDirty (obj);
AssetDatabase.SaveAssets ();
AssetDatabase.Refresh ();
} }& static public void ModifyScene&T& (Action&Component&callBack) where T: MonoBehaviour {
EditorSceneManager.SaveOpenScenes ();
foreach (EditorBuildSettingsScene editorBuildSettingsScene in EditorBuildSettings.scenes)
Scene scene=EditorSceneManager.OpenScene (editorBuildSettingsScene.path);
T[] scripts =
Resources.FindObjectsOfTypeAll&T& ();
for (int i = 0; i & scripts.Length; i++)
callBack (scripts[i]);
EditorSceneManager.SaveScene(scene);
AssetDatabase.SaveAssets ();
AssetDatabase.Refresh ();
} }& static public void ModifyScriptableObject&T& (Action&ScriptableObject&callBack) where T: ScriptableObject {
string[] guids = AssetDatabase.FindAssets ("t:ScriptableObject");
foreach (string guid in guids) {
string path = AssetDatabase.GUIDToAssetPath (guid);
if (path.EndsWith (".asset")) {
T script = AssetDatabase.LoadAssetAtPath&T& (path);
if (script != null) {
callBack (script);
EditorUtility.SetDirty (script);
AssetDatabase.SaveAssets ();
AssetDatabase.Refresh ();
} }&}#endif
序列化对象 ,把obj放到hero.objects[0]里面,然后在把obj删除就行了
123456789101112131415161718
using UnityEngine;using System.Collections;using UnityEngine.Serialization;using System.Collections.Generic;using UnityEngine.SceneManagement;&public class NewBehaviourScript : MonoBehaviour { public GameObject obj; public Hero hero;}&&[System.Serializable]public class Hero{ public List&GameObject& objects;}
ScriptableObject
12345678910111213
using UnityEngine;using System.Collections;using System.Collections.Generic;&[CreateAssetMenu]public class MyAsset : ScriptableObject {&& public GameObject obj; public Hero hero;&&}
OK这样数据就拷贝过去了。然后就可以把旧的数据结构删除了。
做到这里其实还没有完,因为这里就算在脚本里删除了变量名, 那这个变量名之前序列化的数据还在prefab里序列化这。除非修改保存一下才行,所以最好在批量执行一下
EditorUtility.SetDirty (obj);
另外,如果大家有更好的方法处理这个,欢迎再下面留言给我!
Unity版本 5.3.1
本文固定链接:
转载请注明:
雨松MOMO提醒您:亲,如果您觉得本文不错,快快将这篇文章分享出去吧 。另外请点击网站顶部彩色广告或者捐赠支持本站发展,谢谢!
作者:雨松MOMO
专注移动互联网,Unity3D游戏开发
如果您愿意花10块钱请我喝一杯咖啡的话,请用手机扫描二维码即可通过支付宝直接向我捐款哦。
您可能还会对这些文章感兴趣!【Unity3D培训】如何解决Unity3D场景加载中的问题?_深圳Unity3D培训机构
【Unity3D培训】如何解决Unity3D场景加载中的问题?
发布:深圳Unity3D培训
来源:达内新闻
【Unity3D培训】如何解决Unity3D场景加载中的问题?
你若何对一个“关卡”停止编程?
这在游戏引擎中平日不是一个成绩,但Unity必要你将每一个“关卡”断绝为一个场景。并且Unity的场景有一些奇怪的计划抉择(或许便是bug?) - 感到他们引擎的场景是为玩具名目计划的,而不是为产等级其余游戏所计划。
这里有一个甚么起作用、甚么不起作用、和我若何办理/在Unity内做得更好的意识流。。。这些内容没有颠末细心研讨,大多是来自影象或我本身的拍脑壳。 以是。。。这篇文章外面记载的内容能够不是全体是真的:)。
当我切换到Unreal4的时刻,我将应用如许的帖子作为基准来比拟Unity为甚么会失败,和何等糟糕 - 反之亦然。
更新:我增加了更多的方法和设法主意/批评
举个简略的例子来讲:
1.加载场景的时刻,游戏中的一切内容都将被烧毁。
2.场景不克不及带参数。
3.场景不克不及保存状况。
4.场景不克不及在代码中结构或是改动。 法式化的游戏? 哈哈! 基本没有机遇!
5.你不克不及一次编纂多个场景(这是荒诞的,给开辟带来不用要地苦楚)。
6. 。。。和一堆其余成绩,此中许多成绩是上述成绩的反作用。
更多Unity的bug使得你在处置这个成绩的时刻感到像是在天堂里
1.当场景加载的时刻,没有方法奉告Unity要运转甚么代码。
这是必须的,由于Unity回绝让你通报参数。
由于没有方法通报参数,以是你必须依附Awake(),Start()和OnEnable()方法。
这三种方法被界说为在工具之间以“随机”的次序停止运转。
假如你有一个必要被查找、加载和定位的参数,能够将其放在Awake()函数当中。
假如必要对这个参数做全局援用,则必须在Start()函数运转时代设置它,不然不克不及包管它已被找到。
任何必要应用该参数的代码都不克不及写在OnEnable()以外的其余方法中。
。。。然则:许多(绝大多数?)理应在Start()方法中的代码,假如写在OnEnable()中就不克不及失常工作了,由于Start()和OnEnable()这两个方法做的是分歧的工作!
Unity的场景加载太烦人了。
一些罕见的办理方法
Unity5:增量加载
你能够加载一个场景,而后在这个的根基之上加载另一个场景。在某种程度上这个功能在UnityPro中不停存在(好比容许“关卡加载器”的场景等等),然则Unity5对这一点停止了进级和扩大。
依据我的懂得,Unity5并无办理这些成绩,但它确切加重了这些成绩。 分外是,我曾经看到了编纂器的改动记载,以改良一次加载多个场景的处置。但我本身尚未测验考试过这块(我还应用Unity4的版本)。从我看过的视频来看,它看起来像是一个明白的改良,但间隔我称之为“尺度”的游戏引擎仍旧有相称长的一段光阴。
假如你能应用Unity5,请看看你能够走多远。而后把无关你的提醒和技能经由进程推特发给我。
不要抉择“在加载的时刻删除统统(DontDestroyOnLoad)”
你能够标志随意率性数目的游戏物体为“嘿,Unity! 当你删除统统(这是愚笨的主见,然则可行)的时刻,请不要删除这些游戏物体!
在理论上,这意味着你能够编写本身的迷你游戏引擎(你为甚么要再次应用Unity,由于你不停想从新发明轮子,对吗?),而后把一切的游戏数据存储为一个“不要烧毁”的工具,而后在新场景完成加载后剖析并加载适才谁人“不要烧毁”的工具。
这不办理任何成绩-它只是将成绩转移到一个新的处所,但至多它们如今是在你的代码中停止处置,而不是在Unity的代码中停止处置。你终极会写本身的迷你游戏引擎。你从Unity获得的是险些零赞助,并。。。使这个成绩更难。。。你必须保持与Unity的专有数据处置的兼容:初始化协定,糟糕的序列化等等。
这是做“不要在加载的时刻删除统统(DontDestroyOnLoad)”的“真实的”方法,“不要在加载的时刻删除统统(DontDestroyOnLoad)”是内置于编程语言的尺度方法。 它让我感到奇怪的是,Unity在有了一个更尺度的方法今后,还增加了“不要在加载的时刻删除统统” 是否是一个低级法式员谁不晓得若何应用“动态”关键字?还是有一些使人憎恶的埋在Unity焦点引擎的器械打破了动态? (提醒:我险些能够包管它会是序列化系统中的某个处所的一个bug,我很憎恶这一点,假如你尚未注意到的话)。 在Unity的架构中险些一切的器械都邑与谁人怪物打交道!)
它彷佛对我来讲老是工作失常。但它是可骇的:它甚么时刻会停止工作? 你怎样能力晓得这一点? 有甚么Unity的bug埋伏在这里?
自包括的场景
拿掉一切的游戏逻辑,咱们曾经把数据作为参数通报给了你的场景(在任何失常的引擎中)。。。而不是将参数嵌入在场景以内。
当场景加载的时刻,它运转这个逻辑,而后发明“哦! 我彷佛缺乏许多焦点数据。我最佳在运转的进程从新创立它!
这是一个波折的逻辑,对那些新参加你的团队的开辟者来讲能够异常凌乱(并且也能够凌乱到了你本身,假如你从名目中苏息了一段光阴再返来)。但它有一些明显的利益:
你能够在游戏中运转场景。。。或。。。间接从Unity编纂器运转它,它将表示的(险些)雷同。能够以这类方法停止更快的测试+调试
场景保持着自包括的特色。 这是Unity的计划师“盘算”你应用场景(固然这对付游戏来讲是一个异常糟糕的办理方案)的方法。 这对你的游戏的源代码节制和多用户编纂有一些微小的利益:假如你如许工作的话,你会碰到大批的Unity焦点bug。
理论上:更多的“场景特定”的代码位于场景中(在Unity编纂器中)。当你的名目变大的时刻,在理论上:这使得懂得发生了甚么更轻易,由于代码+工具对付相互都是当地部分的。我不完全确认这一点:与Unity那种比拟差的支配代码+数据的方法比拟。。。在实践中,这个部分性能够不明显(Unity编纂器“暗藏”了部分性,以是你作为开辟职员并无从中获得甚么利益)。
应用预制件(Prefabs)
好吧,我碰到过那些宣称如许做的人-在编纂器中创立场景,而后将一切内容转换为预制件,而后在场景加载的时刻加载预制件,通报分歧的“要加载的预制件的名字”列表。
哦,请不要这么做!
起首:Unity中的预制件对付这类繁杂的环境会被严重毁坏。他们不克不及失常工作,你应当尽能够防止应用预制件-除那些最简略的用例(非嵌套、简略的小预制件)。
第二:哇,这很波折。 你正在滥用“模板化的工具系统”来绕过“数据层”和“场景加载器”中的计划缺点。它能够是一种天赋做法-但它是那种不寻常的天赋做法,它很轻易在将来的更新后的引擎被毁坏,而Unity能够正当地说:“嗯?你为甚么要如许做?“
假如它在你的名目中失常工作,这太棒了! 但对我来讲,这老是一个隐患。能够我错过了一些好的做法,这能够是一个比我意想到的更好的道路。在大多数环境下,这是现实,Unity不克不及处置准确繁杂的预制件是现实。Unity5据称修复了一些预制件方面的差错,以是。。。我会在某个时刻再考虑应用预制件。但是,Unity中的预制件方面的汗青是异常丑恶的,我会异常谨严的信任他们。
这些成绩的办理方法
Unity不支持字典和哈希表
这是一个巨大的披发着臭味的成绩(纵观全体Unity的汗青!)。
它改变了上述办理方法中的利害均衡。你不克不及简略地增加定名参数到你的动态方法和 “不要在加载的时刻删除统统”的列表中-由于Unity会穿过编程语言来间接删除/烧毁/毁坏它们。
(我说过我憎恶Unity的破天荒的序列化系统吗?好吧,我异常憎恶这个系统)。
末了,我发明“不要在加载的时刻删除统统(DontDestroyOnLoad)”最有吸引力的部门是你能够应用:
GameObject param1 = ... ;
GameObject persistentObject = ... ;
param1.transform.parent = persistentObject.
//param1.tag = ... oh, no - can't do this. Unity's tags are hardcoded (that is NOT what Tag means, guys!)
param1.name = "Parameter 1";
而后,你能够应用相似如下的内容来对它停止检索:
GameObject persistentObject = ... ;
GameObject param1 = persistentObject.Find( "Parameter 1" );
(假定你不知何以获得了一个耐久工具的援用。。。举个简略的例子来讲,使它成为一个单例)。
我信任你也能够应用动态工具来做到这一点(?)然则。。。把一全体工具干系图暗藏在一个动态成员变量外面能够会进入“这能够会裸露Unity序列化的Bug”的范畴。 最佳防止这么做:不要挥霍太多的光阴在调试Unity上。
抱负/准确的办理方案
数据便是数据
咱们回到谁人Unity中重复呈现的成绩,它对引擎的毁坏这么大:Unity回绝认可“数据”便是“数据”。 它保持:“不,不! 数据是代码和工具另有图形和物理工具和。。。和。。。和。。。和。。。“。
(让咱们廓清一点:有经验的法式员看不起Unity的方法,并且一样平常都是异常刻薄不包涵。这不是由于咱们对其余引擎和方法狂热- 而是Unity的编程方法在20世纪80年月就基本上死了。它没有做甚么限定,很快就被证实很难创立繁杂的法式好比说是视频游戏)。
抱负环境下,咱们会将游戏的数据存储为数据,并在加载的时刻将数据通报给场景。 Unity阻拦咱们如许做。咱们为模仿这统统而做的统统(比方嵌入JSON(反)序列化器)是搬掉Unity路障的办理方法。
今后的试验
我曾经在曩昔的Unity名目中测验考试了大多数以上的方法,没有一个做得分外好。
此次测验考试甚么?
这里是我今朝的需要:
1.当场景加载的时刻,我必要注入玩家脚色。这是一个繁杂的工具,包括衬着、物理和法式化网格。
2.当场景加载的时刻,我必要零丁设置装备摆设一些不可见的状况:好比玩家的特性(比方命中点、得分)。。。这些不可见的状况关卡会克隆并用作可见状况(在关卡变更时代的命中点。当你开端一个关卡时刻的命中点会“保存”那些不变的值)。
3.当场景加载的时刻,。。。我也有不可见的状况,用于天生其余状况。举个简略的例子来讲,对于到今朝为止曾经摸索了这个关卡多少的信息、 战斗迷雾等等。
4.当玩家完成关卡的时刻,我必要抉择一些数据保存到主菜单,并保存到磁盘中。
5.当玩家完成关卡的时刻,我必要存储“曩昔”和“今后”之间的差别,以便我能够付与各类徽章/成绩和一次性嘉奖等等。其余,以便我能够展现“ 这是你曾经完成的成绩!“的终极停止界面。
我曾经废弃了:我写了一个本身的迷你引擎来办理Unity可骇的场景治理。回想我的许多Unity名目,我曾经用了许多天,能够跨越一个礼拜,不能不赓续地从新完成这个焦点功能,由于Unity版本的场景治理环境使人难以置信的凌乱。
这是诸多bug的此中一个,便是这些bug让我感到Unity的技能负责人从来不本身写游戏。假如他们如许本身写游戏的话,他们不会忍耐这类渣成绩的。
简短的描写:
&&& 每次场景开端加载的时刻,写一个类加载钩子(应用C#)。
&&& 调试Unity加载场景的时刻一切正式文档以外的API挪用。这能够必要很长期。
&&& 做反向工程来晓得Unity场景的哪些部门是“有用”和何时“有用”。
&&& 编写每一个贸易游戏引擎(Unity除外!)用于治理场景加载的那种代码。
&&& 将其包装在API中。
&&& 。。。
&&& 永久不要在Unity的场景系统外面再处置这个成绩,永久永久都不要!
有用的功能
对两个游戏物体停止“比对”探求差别化
这将是异常有用的。这将使得上面的许多办理方法加倍轻易。
这个功能也内置于Unity当中。咱们晓得这一点:序列化系统依附于这个功能。
然则他们不容许咱们拜访(就我所知:我没有看到一个大众API会去挪用这个功能)。
&“克隆”一个游戏物体,保持对原始游戏物体的援用
一切面向工具编程语言的工具(包括C#)会跟踪它们所创立的类。
假如Unity再次应用“clone object1 to create object2”来做异样的工作,这将使许多上面的方法加倍轻易,也加倍不轻易出错。
想知道更多关于IT行业的信息吗?想远远不如行动,行动起来,一起加入达内,一起进入IT行业,跟着达内的脚步,一起走进如今的互联网信息时代,带给你不一样的色彩生活——【】
增强现实技术(AR)及扩展应用
【深圳Unity3D培训】了解AssetBundle
【深圳Unity3D培训】基于Socket通信的小实例
【深圳Unity3D培训】为什么最近好多游戏公司都倒闭了?10个理由
Copyright (C)
All Rights Reserved
选择城市和中心
达内北京亦庄大学生实训基地
达内北京网络营销中心
达内北京会计中心用户名:jxw167
文章数:39
评论数:46
访问量:79311
注册日期:
阅读量:1297
阅读量:3317
阅读量:585365
阅读量:471130
51CTO推荐博文
& 我们在使用Unity读取文件或者消息传递的时候,经常说到序列化。什么是序列化?序列化的意思就是我们的数据是按照一定的顺序进行赋值的,这个顺序是一定的。它主要是为了方便变量赋值。在Unity中我们也经常使用这种方法。例如我们可以这样写:在我们需要序列化的前面加上[System.Serializable]用于告诉C#以下结构是我们需要序列化的。下面我们就说一下如何使用XML进行序列化。我们不能直接写XML文件,我们一般是通过Excel表格将其转化成XML格式,我们需要转化成啥格式才能比较好的序列化?我们是这样操作的:其一、定义一个Dictionary 我们将根据结构体的名字将其整个结构体放到里面。其二、每个结构体它都有自己对应的ID,每个ID唯一标识一个结构体数据,我们就是按照ID进行读取数据。我们可以利用Swicth case语句读取存放数据,代码如下:大家看上面的语句,有一个DeserializeObject这个就是C#使用的反序列化函数,我们就是通过它将我们的XML里面的字段保存起来。以下是调用的函数:那么我们只需要调用我们已经保存到Dictionary里面的值就可以了。比如:另外附上xml文件格式:是不是很方便?本文出自 “” 博客,请务必保留此出处
了这篇文章
类别:┆阅读(0)┆评论(0)Unity中的序列化 - CSDN博客
Unity中的序列化
小编的话:这是一篇关于序列化的文章,有原文和译文(有译错的地方还请各位包含)。文章主要介绍的部分由:序列化是Unity的核心,序列化对字段的要求,遇到特殊情况的序列化,如何应对等等。文章较长,大家要耐心读下去啊↖(^ω^)↗。
& && & In the spirit of sharing more of the tech behind the scenes, and reasons why some things are the way they are, this post contains an overview of Unity’s
serialization system. Understanding this system very well can have a big impact on the effectiveness of your development, and the performance of the things you make.&&Here we go.
& && & 我愿在幕后为大家分享更多有关技术的资讯和告诉大家有些事为什么是它们现在这样的原因。这篇文章是关于Unity序列化系统的概述。我们很好的了解这个系统,能帮助大家有效开发并更好展现所做的成品。现在我们马上开始。
& && & Serialization of“things” is at the very core of Unity. Many of our features build ontop of theserialization system:
& && & 序列化是Unity的核心。Unity的许多特色都建立在序列化系统之上。
·& && &&&Storing data stored in your scripts.&This onemost people are probably somewhat familiar with.
& && &&在脚本中存储数据。这一点,大多数人都非常熟悉。
·& && &&Inspector window.&The inspector window doesn’t talk tothe C# api to figure out what the values of the properties of whatever it isinspecting
is. It asks the object to serialize itself, and then displays theserialized data.
& && &&&检视器窗口。检视器窗口无法与c# api交互,就不能查出无论哪个它正在检验的属性值。它要求对象序列化,然后显示序列化数据。
·& && &&Prefabs.&Internally,a prefab is the serialized data stream of one (or more)
game objects andcomponents. A prefab instance is a list of modifications that should be made onthe serialized data for this instance. The concept prefab actually only existsat editor time. The prefab modifications get baked into a normal serializationstream
when Unity makes a build, and when that gets instantiated, theinstantiated game objects have no idea they were a prefab when they lived inthe editor.
& && &&&&预制。内层结构中,预制是一个(或多个)游戏对象和组件的序列化数据流。预制实例是需进行实例化数据的修改列表。但这个概念只在编辑环节中用到。当Unity做一个构建及构建实例化时,预制修改表进入正常的序列化流中,而且当在编辑器中运行时,实例化的游戏对象不知道它们是预制。
·& && &&Instantiation.&When youcall Instantiate() on either a prefab, or a gameobject that lives in the scene,or on anything else for that matter
(everything that derives fromUnityEngine.Object can be serialized), we serialize the object, then create anew object, and then we “deserialize” the data onto the new object. (We thenrun the same serialization code again in a different variant, where we use
itto report which other UnityEngine.Object’s are being referenced. We then checkfor all referenced UnityEngine.Object’s if they are part of the data beingInstantiated(). If the reference is pointing to something “external” (like atexture) we keep that reference
as it is, if it is pointing to something“internal” (like a child gameobject), we patch the reference to thecorresponding copy).
& && &&实例化。当你要么访问预制,要么访问场景中的游戏物体,要么访问任何可序列化的UnityEngine.Object时,都可以实例化。我们给对象实例化,然后创建一个新的对象,最后我们“并行化”数据到新的对象中。(我们在不同的变体中,再次运行相同的序列化代码,我们用它来写其他UnityEngine.Object’s中引用的报告。如果他们中一部分数据被实例化,我们检查所有引用的UnityEngine.Object’s。如果引用指向“外部”的东西(如文本),我们就保持引用。如果指向“内部”的东西(比如子游戏对象),我们修正引用相应的副本)。
·& && &&&Saving.&If
youopen a .unity scene file with a text editor, and have set unity to “force textserialization”, we run the serializer with a yaml backend.
& && && &存储。如果你用文本编辑器打开一个Unity场景文件,Unity设置为“强制文本序列化”,我们用在服务器用yaml格式进行序列化。
·& && &&&Loading.&Might notseem surprising, but backwards compatible
loading is a system that is built ontop of serialization as well. In-editor yaml loading uses theserialization system, as well as the runtime loading of scenes and assets.Assetbundles also make use of the serialization system.
& && &&载入。听起来有些奇怪的是,向后兼容加载也是一种建立在序列化上的系统。yaml格式的加载使用序列化系统,运行时间的加载和设置也使用序列化系统。此外,资源包也要利用序列化系统。
·& && &&Hot reloading
of editor code.&When youchange an editor script, we serialize all editor windows (they derive fromUnityEngine.Object!), we then destroy all the windows, unload the old c# code,load the new c# code, recreate the windows, and finally deserialize
thedatastreams of the windows back onto the new windows.
& && &&&编辑器代码的频繁重载。当改变编辑脚本时,我们得重新序列化所有编辑器窗口(他们继承于UnityEngine.Object !),然后我们关闭所有窗口,卸载旧的c#代码,加载新的c#代码,重新创建窗口,最后反序列化数据流到新窗口中。
·& && &&&Resource.GarbageCollectSharedAssets().&This is our
native garbage collector and is different to the C# garbage collector. Itis the thing that we run after you load a scene to figure out which things fromthe previous scene are no longer referenced, so we can unload them. The nativegarbage collector runs the
serializer in a mode where we use it to have objectsreport all references to external UnityEngine.Objects. This is what makestextures that were used by scene1, get unloaded when you load scene2.
& && &&&Resource.GarbageCollectSharedAssets()函数
& && & 本地的垃圾回收站和c#垃圾回收站是不同的。区别就是我们在加载场景并找出哪些东西是从先前的场景到今不再引用的之后,我们卸载它们。本地垃圾回收站以序列化器模式运行,这种模式的原理是用它来进行报告到外部UnityEngine.Objects上的所有引用。例如,这正是场景1使用的文本,当运行场景2时,卸载场景1。
& && & The serialization system is written in C++, we use it for all our internal objecttypes (Textures, AnimationClip, Camera, etc). Serialization happens at theUnityEngine.Object
level, each UnityEngine.Object is always serialized as awhole. They can contain references to other UnityEngine.Objects and thosereferences get serialized properly.
& && & 序列化系统是用c++写的,我们用它编辑所有内部对象类型(文本、动漫剪辑、相机等)。序列化存在于UnityEngine Object层面中,每一UnityEngine Object中总作为一个整体进行序列化。它们包括对UnityEngine的引用和恰当地序列化。
& && & Now you may say that none of this concerns you very much, you’re just happy that it works andwant to get on with actually creating some content. However, this will concernyou,
as we use this same serializer to serialize MonoBehaviour components,which are backed by your scripts. Because of the very high performancerequirements that the serializer has, it does not in all cases behave exactlylike what a C# developer would expect from
a serializer. Here we’lldescribe how the serializer works and some best practices on how to make thebest use of it.
& && &现在你也许会说,我对这些都不太感兴趣,你只是对它能运行并继续创造一些新内容而感到满意。然而,当我们使用相同的序列化器去序列化在脚本尾部的MonoBehaviour组件时,你将会比较在意。由于序列化器有很高的执行要求,在通常情况下,它完全不像C#开发人员对序列化器的要求。在这里我们将告诉大家序列化器是如何工作的,以及通过实例,讲解如何更好利用它。
What does afield of my script need to be in order to be serialized?
序列化操作中,对脚本的字段有何要求?
·& && &&&Be public, or have [SerializeField] attribute
·& && &&&公共的,或带有[SerializeField]的属性
·& && &&&Not be static
·& && &&&非静态
·& && &&&Not be const
·& && &&&非常量
·& && &&&Not be readonly
·& && &&&非随机
·& && &&&The fieldtype needs to be of a type that we canserialize.
·& && &&&字段类型必须是可序列化的类型
Which fieldtypescan we serialize?
何种字段类型可以序列化?
·& && &&&Custom non abstract classes with [Serializable]attribute.
·& && &&&带有可序列化属性的自定义非抽象类
·& && &&&Custom structs with [Serializable] attribute. (new inUnity4.5)
·& && &&&带有可序列化属性的自定义结构体(在新的Unity4,5中)
·& && &&&References to objects that derive from UntiyEngine.Object
·& && &&&引动到继承于UntiyEngine.Object的对象
·& && &&&Primitive data types (int,float,double,bool,string,etc)
·& && &&&原始数据类型(int,float,double,bool,string等等)
·& && &&&Array of a fieldtype we can serialize
·& && &&&可序列化的数组
·& && &&&List&T& of a fieldtype we can serialize
·& && &&&可序列化的列表&T&
& && & So far so good.So what are these situations where the serializer behavesdifferently from what I expect?
& && & 到目前为止一切都很顺利。若是碰到序列化器的操作和我们预想的不一样时,该怎么处理呢?
& && & Custom classes behave like structs
& && & 自定义类的功能就像结构体
[C++]&纯文本查看&复制代码
[Serializable]
&&&&public
MyScript : MonoBehaviour
&&&&public
& && &&&If you populate the animals array with three references to a single Animal object, in theserializationstream you will find 3 objects. When it’s deserialized, there arenow
three different objects. If you need to serialize a complex object graphwith references, you cannot rely on Unity’s serializer doing that allautomagically for you, and have to do some work to get that object graphserialized yourself. See the example below
on how to serialize things Unitydoesn’t serialize by itself.
& && & 举个常用的例子。用3个引用表示动物数组到单个动物的对象,在序列化流程后,会有三个对象。当反序列化后,还会有3个不同的对象。如果用复杂的带有引用的对象图来序列化,就不能依赖于Unity的序列化器来替你自动完成这过程,只能自己去做对象图的序列化。接下来的例子,告诉我们Unity无法序列化时,如何进行序列化操作。
& && & Note that thisis only true for custom classes, as they are serialized “inline” because theirdata becomes part of the complete serializationdata for the MonoBehaviour theyare
used in. When you have fields that have a reference to something that is aUnityEngine.Object derived class, like a “public Camera my Camera”, the datafrom that camera are not serialized inline, and an actual reference to thecamera UnityEngine. Object is serialized.
& && & 要注意的是,这只适用于自定义类。之所以作为内联方式的序列化,是因为他们的数据在MonoBehaviour中作为部分的完整序列化数据而被使用。当有些字段是引用于UnityEngine.Object的派生类时,形如“public Camera myCamera”,来自于camera类中的数据就不是序列化的“行内”,并且引用到camera类的UnityEngine.Object中的数据是已序列化的。
No support fornull for custom classes
不支持空字符的自定义类
& && & Pop quiz. Howmany allocations are made when deserializing a MonoBehaviour that uses thisscript:
& && & 有个普遍的疑惑。当使用脚本序列化MonoBehaviour时,到底用了多少配置呢?
[C++]&纯文本查看&复制代码
Test : MonoBehaviour
&&&&public
[Serializable]
&&&&public
Trouble t1;
&&&&public
Trouble t2;
&&&&public
Trouble t3;
& && &&&It wouldn’t bestrange to expect 1 allocation, that of the Test object. It also wouldn’t bestrange to expect 2 allocations, one for the Test object and one for a Troubleobject.
The correctanswer is 729. The serializer does not support null. If it serializes an objectand a field is null, we just instantiate a new object of that type andserialize that.
Obviously this could lead to infinite cycles, so we have arelatively magical depth limit of 7 levels. At that point we just stopserializing fields that have types of custom classes/structs and lists andarrays. [1]
& && & 大家对其中的一个配置,即测试对象,肯定不会感到惊奇。对于另外个配置,大家也不会感到陌生。一个配置叫做测试对象,另一个叫做诊断对象。
正确答案是729。序列化器无法识别空字符。如果它序列化的一个对象或字段是空字符的话,我们只是在实例化那种类型的对象及序列化它。很明显,这将导致无限循环,就像数字7一样有个神奇的无限循环规律一样(当某个数除以7时)。从这点来看,我们不使用有自定义类/结构体和有列表、数组的序列化字段。
& && &&&Since so many ofour subsystems build on top of the serialization system, this unexpectedly bigserializationstream for the Test monobehaviour will cause all these subsystemsto
perform more slowly than necessary. When we investigate performance problemsin customer projects, we almost always find this problem and we added a warningfor this situation in Unity 4.5.&We actually messed up the
warning implementation in such a way that it gives youso many warnings, you have no other option but to fix them right away. We’llsoon ship a fix for this in a patch release, the warning is not gone, but youwill only get one per “entering playmode”, so you
don’t get spammed crazy.You’d still want to fix your code, but you should be able to do it at a timewhere it suits you.
& && & 因为我们很多的子系统在构建序列化系统,这将给Test Monobehaviour带来巨大的序列化流,并引起子系统比正常的运行速度慢很多。当我们在客户项目中调查运行问题时,我们总是发现这个毛病并把这种情况反馈到Unity4.5,作为警告。实际上,我们这样做反而把警告给搞砸了。出现了更多的警告提示,我们别无选择,只得去修复它们。不久,我们将要发布一个修复补丁,警告还是不会消失,只不过用户只能每次“进入玩家模式”,就不必再为那些警告提示发疯了。你们或许还是想修改代码,但得在适合你们的时间段去完成它。
No support forpolymorphism
不支持多态
& &&& &If you have a
& && & 假如你有个这样一段代码
[AppleScript]&纯文本查看&复制代码
Animal[] animals
& && &&&and you put inan instance of a dog, a cat and a giraffe, after serialization, you will havethree instances of Animal.
& && &&&你在实例中加入了狗,猫和长颈鹿。在序列化之后,你将在动物类中有三个实例。
& && &&&One way to deal with this limitation is to realize that it only applies to “custom classes”,which get serialized inline. References to other UnityEngine.Object’s getserialized
as actual references and for those, polymorphism does actually work.You’d make a ScriptableObject derived class or another MonoBehaviour derivedclass, and reference that. The downside of doing this, is that you need tostore that monobehaviour or scriptable
object somewhere and cannot serialize itinline nicely.
& && & 解决此种限制的一种方法是意识到它只应用于得到内联方式的序列化“自定义类”。引用到其他UnityEngine.Object进行真实的序列化,多态也在其中有所使用。你会做一个ScriptableObject的派生类或是MonoBehaviour的派生类。但这样做的不足之处在于,你需要在某地保存monobehaviour或能脚本化的对象,但不能很好进行内联方式的序列化。
& && && && && && && && && && && && && && && && && && && && && && && && && && && && && && &
& && & The reason forthese limitations is that one of the core foundations of the serializationsystem is that the layout of the datastream for an object is known ahead oftime,
and depends on the types of the fields of the class, instead of whathappens to be stored inside the fields.
& && & 有这些局限性的原因之一是,序列化系统的核心基础是需提前知道对象的数据流的布局,它取决于这个类的字段类型,而不是考虑存储在字段中会引起什么变化。
I want toserialize something that Unity’s serializer doesn’t support. What
我想要序列化一些Unity序列化器无法支持的代码。该怎么做?
& && &&&In many casesthe best approach is to use serialization callbacks. They allow you to benotified before the serializer reads data from your fields and after it is donewriting
You can use thisto have a different representation of your hard-to-serialize data at runtime thanwhen you actually serialize. You’d use these to transform your data intosomething
Unity understands right before Unity wants to serialize it, you alsouse it to transform the serialized form back into the form you’d like to haveyour data in at runtime, right after Unity has written the data to your fields.
Let’s say youwant to have a tree datastructure. If you let Unity directly serialize the datastructure, the “no support for null” limitation would cause your datastream tobecome
very big, leading to performance degradations in many systems:
& && & 在多数情况下,最有效的方法是使用序列化回调。他们让你在被通知之前,序列化器从你的字段中读取数据字段并在之后写出读取的字段。
你可以在运行期间,选用不容易序列化的数据,而不是那些你真正在做序列化时的数据。你用序列化回调把数据转换成在Unity将要序列化之前,它能够理解的数据。你同样用它在运行时间之前,转换成你想要的序列化的格式。之后,Unity会在你的域内写好转换的数据。
假设你想要有个树型数据结构。如果你让Unity直接序列化数据结构,“不支持空字符”的限制会致使你的数据流变得非常大,导致在许多系统中无法实现功能。
[C++]&纯文本查看&复制代码
System.Collections.G
VerySlowBehaviourDoNotDoThis : MonoBehaviour
&&&&[Serializable]
&&&&public
&&&&&&&&public
string interestingValue = &value&;
&&&&&&&public
List&Node& children = new
List&Node&();
&&&&public
Node root = new
&&&&&&&&Display
Display(Node node)
&&&&&&&&GUILayout.Label
&&&&&&&&node.interestingValue
= GUILayout.TextField(node.interestingValue, GUILayout.Width(200));
&&&&&&&&GUILayout.BeginHorizontal
&&&&&&&&GUILayout.Space
&&&&&&&&GUILayout.BeginVertical
&&&&&&&&foreach
(var child in node.children)
&&&&&&&&&&&&Display
&&&&&&&&if
(GUILayout.Button (&Add
&&&&&&&&&&&&node.children.Add
&&&&&&&&GUILayout.EndVertical
&&&&&&&&GUILayout.EndHorizontal
& && & Instead, you tell Unity not to serialize the tree directly, and you make a seperate field to store the tree in a serialized format, suited for Unity’s serializer:
& && & 另外,当你告知Unity不直接序列化树型,并在顺序化格式中做了个单独字段来保存树型,以下是适合Unity的序列化器:
[C++]&纯文本查看&复制代码
System.Collections.G
BehaviourWithTree : MonoBehaviour, ISerializationCallbackReceiver
&&&&public
&&&&&&&&public
string interestingValue = &value&;
&&&&&&&&public
List&Node& children = new
List&Node&();
&&&&[Serializable]
&&&&public
SerializableNode
&&&&&&&&public
string interestingV
&&&&&&&&public
&&&&&&&&public
indexOfFirstC
root = new
&&&&public
List&SerializableNode& serializedN
&&&&public
OnBeforeSerialize()
&&&&&&&&serializedNodes.Clear();
&&&&&&&&AddNodeToSerializedNodes(root);
AddNodeToSerializedNodes(Node n)
&&&&&&&&var
serializedNode = new
SerializableNode () {
&&&&&&&&&&&&interestingValue
= n.interestingValue,
&&&&&&&&&&&&childCount
= n.children.Count,
&&&&&&&&&&&&indexOfFirstChild
= serializedNodes.Count+1
&&&&&&&&};
&&&&&&&&serializedNodes.Add
(serializedNode);
&&&&&&&&foreach
(var child in n.children)
&&&&&&&&&&&&AddNodeToSerializedNodes
&&&&public
OnAfterDeserialize()
&&&&&&&&if
(serializedNodes.Count & 0)
&&&&&&&&&&&&root
= ReadNodeFromSerializedNodes (0);
&&&&&&&&else
&&&&&&&&&&&&root
ReadNodeFromSerializedNodes(int
&&&&&&&&var
serializedNode = serializedNodes [index];
&&&&&&&&var
children = new
List&Node& ();
&&&&&&&&for(int
i=0; i!= serializedNode.childC i++)
&&&&&&&&&&&&children.Add(ReadNodeFromSerializedNodes(serializedNode.indexOfFirstChild
+ i));
&&&&&&&&return
&&&&&&&&&&&&interestingValue
= serializedNode.interestingValue,
&&&&&&&&&&&&children
= children
&&&&&&&&};
&&&&&&&&Display
Display(Node node)
&&&&&&&&GUILayout.Label
&&&&&&&&node.interestingValue
= GUILayout.TextField(node.interestingValue, GUILayout.Width(200));
&&&&&&&&GUILayout.BeginHorizontal
&&&&&&&&GUILayout.Space
&&&&&&&&GUILayout.BeginVertical
&&&&&&&&foreach
(var child in node.children)
&&&&&&&&&&&&Display
&&&&&&&&if
(GUILayout.Button (&Add
&&&&&&&&&&&&node.children.Add
&&&&&&&&GUILayout.EndVertical
&&&&&&&&GUILayout.EndHorizontal
& && &&&Beware that theserializer, including these callbacks coming from the serializer, usually donot run on the main thread, so you are very limited in what you can do in termsof
invoking Unity API. (Serialization happening as part of loading a scenehappens on a loading thread. Serialization happening as part of you invokingInstantiate() from script happens on the main thread). You can however do thenecessary data transformations do
get your data from anon-unity-serializer-friendly format to a unity-serializer-friendly-format.
& && & You made it tothe end!
& && & Thanks forreading this far, hope you can put some of this information to good use in yourprojects.
& && & Bye, Lucas. (@lucasmeijer)
& && & 注意那些序列化器,特别是来自序列化器中的回调,通常不在主线程上运行。所以就调用Unity API而言,你所能做的是要受到限制的。(序列化在加载一个场景时执行,也在加载线程执行。序列化还发生在从脚本中调用Instantiate()函数时,还发生在主线程中。)这样一来,你有必要去将数据从非友好交互型的Unity序列化器格式转换成友好交互型的Unity序列化器格式。
& && & 这样做就完成了!
& && & 感谢你的阅读,希望这些信息会对你的项目有所帮助。
& && & 再见,卢卡斯。(@lucasmeijer)
PS: We’ll addall this information to the documentation as well.
PS:我们会将这些信息添加到文档中。
原文链接:
本文已收录于以下专栏:
相关文章推荐
相关资料:Invoke
和 BeginInvoke 的真正涵义 、在多线程中如何调用Winform
Control.Invoke 方法 (Delegate...
SerializeField 序列化域
Inherits from Attribute
Force Unity to serialize a private field.
强制Unity去序列化一...
首先,Unity会自动为Public变量做序列化,序列化的意思是说再次读取Unity时序列化的变量是有值的,不需要你再次去赋值,因为它已经被保存下来。
然后是,什么样的值会被显示在面板上?
已经被序列...
使得变量可以被Inspector界面获得
本文将从Unity编辑器和运行时两个角度出发,主要探讨以下两方面内容:Unity序列化系统内部细节以及Unity如何维护不同对象之间的强引用。另外还会讨论对象与资源的技术实现差别。
本文内容是理解...
这段时间在研究和学习C#的序列化和反序列化的东西。发现这是一个非常友好的数据本地store的方式。但是在使用过程中也有很多有意思的地方,我这里把我越到的问题列一下。我使用的是C#的二进制形式的序列化和...
http://kou-/entry//014611
Unity5.3 から JsonUtility 追加された。
が、List ...
    序列化是为了将对象存储(或传输)到内存、数据库或文件中,把对象状态转化为一组字节的过程。换句话说:就是如何保存对象并恢复其状态以供后续使用。现在的游戏一般都离不开序列化,特别是一些...
他的最新文章
讲师:何宇健
讲师:董岩
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)

我要回帖

更多关于 序列化问题 的文章

 

随机推荐