Serialization

原文链接:https://sometimesicode.wordpress.com/2015/04/11/unity-serialization-part-1-how-it-works-and-examples/

On this series of articles (2, maybe 3) we will discuss a topic that is extremely  important to unity3D development: serialization. This subject may be a bit cloudy for beginners, but understanding it not only helps to figure out how the Unity engine works, but it can also become really handy during a game development process and assist you to build better solutions. We will concentrate our study on the following subjects:

这个系列的文章(2,或许会有3)会探讨一个对于unity3d开发极其重要的话题:序列化。这个主题对于初学者来说或许有一些犯愁,不过明白后不仅对理解unity引擎的工作方式有帮助,还会在游戏开发过程中变得很方便使用并且可以帮助你建立更好的解决方案。接下来将集中研究以下方面:

它是什么?(Part1)

Unity中如何工作(Part1)

案例(Part1)

定义一个序列化类型(Part2)

序列化的问题(Part2)

可编写脚本的对象(Part3)

如果对于之前的概念感觉还不错,就可以随意看这些方面。

What is it?

Among other definitions, serialization is the process of converting the state an object to a set of bytes in order to store (or transmit) the object into memory, a database or a file. In another words: it’s how you can save an object to restore its state for later use.

在其他的定义中,序列化是为了将对象存储(或者是传输)到内存、数据库或文件中,把对象状态转化为一组字节的过程。换句话说:就是为了以后使用如何保存对象来恢复它的状态。

Let’s say you have a Vector3 and you need to store it for future use. Which fields would you save into a file to restore its state? X, Y and Z, that’s easy! Apply this rule for any object and if you serialize all the (important) data, you can reload the object exactly how it was before. We name the process of storing the state of the object as“serialization”and the reverse process of building an object out of a file“deserialization”.

假设有一个Vector3并且为了以后使用需要存储它。你会保存哪些字段到文件中来恢复它的状态?X,Y和Z,这太容易了!为每一个对象都应用这种规则,如果序列化了所有(重要)的数据,就可以按照它之前的样子完全正确的进行重载。我们把存储对象状态的进程称为“序列化”,并将文件外建立对象的反转过程称为“反序列化”。

As we already read, this process is really useful to store and transmit data, so think about this: you have an online store deployed on your server, probably running a database manager application aside. Eventually, we need to store the data from memory into the disk (primary storage is volatile) and we do it by serializing our objects into database tables (which basically are files). The same process happens with every application that needs to store data into a disk, and computer games (and engines) are not an exception.

正如已经看过的,这个过程对于存储和传输数据很有用,所以思考一下:在你的服务器有一个在线存储部署,或许可以在旁边运行一个数据库管理器应用程序。最后,需要将数据从内存存储到磁盘中(主存储器是不稳定的),我们就是通过将对象序列化放入数据库表单(基本上是文件)来完成的。相同的过程发生在每一个需要往磁盘里存储数据的应用程序上,电脑游戏(引擎)也不例外。

How Unity Does

Unity, as a Game Engine, needs to load a lot of stuff (scripts, prefabs, scenes) from the disk into the memory within application data. Maybe more important than that, Unity needs to move data between the native C++ side of the engine and the managed C# side. Even though we may think this task is strict to loading and storing assets processes, the serialization is used in many more situations than we think (like inspector window, reloading of editor code and instantiation among other scenarios). You can learn a bit more about Unity Serialization on their own blog. I’d risk to say it’s a mandatory read for developers.

Unity,作为一个游戏引擎,在应用程序数据中需要从磁盘加载很多东西(脚本、预制件、场景)到内存中。或许比那些更重要的,unity需要在引擎的C++主体方面和C#管理方面移动数据。即使我们也许认为这样加载和存储资源的过程已经很严谨了,不过序列化可以用在比我们想的更多的情况下(像检视窗口、重载编辑器代码或实例化其他情景)。你可以在他们自己的博客中学习更多的unity序列化的东西。我冒险说一句,这对于开发者来说是一种强制性的阅读。

The UnityEngine.Object class (which is serializable) provides us with the serialization resource in Unity: any other class than inherits from it–that includes MonoBehaviour, ScriptableObject (more on this later on the series), Shader, Sprite and basically everything in Unity–can also be serialized. Most of its uses are invisible and don’t matter when developing a game, except for a major use: scripting. When you create scripts, you need to keep on mind which fields you want to serialize, and, to do so, your field must:

在unity中UnityEngine.Object类为我们提供了序列化资源:继承自它的任何类——包括MonoBehaviour,ScriptableObject (稍后将详细介绍),Shader,,Sprite,以及几乎unity中每一件事——也可以被序列化。它的大部分应用都是不可见的,并且在开发游戏时不用去在意,除了一个主要的用途:编写脚本。当创建脚本时,需要记住哪个字段想要序列化,然后就按照想法去做,字段必须符合以下几点:

Be public, or have [SerializeField] attribute

Not be static

Not be const

Not be readonly

The fieldtype needs to be of a type that we can serialize.

Which fieldtypes can we serialize? According to Unity’s documentation:

Custom non abstract classes with [Serializable] attribute.

Custom structs with [Serializable] attribute. (New in Unity 4.5)

References to objects that derive from UntiyEngine.Object

Primitive data types (int,float,double,bool,string,etc)

Array of a fieldtype we can serialize

List of a fieldtype we can serialize

A really common data structure isn’t serializable: Dictionaries, even if you declare them as public, and [SerializeField] atribute. So keep that in mind when developing a game.

Ok, this is a lot of information, so let’s break it to a straightforward code example:

设为公有public,或者添加[SerializeField]属性

不要设为静态static

不要设为常量const

不要设为只读readonly

字段类型需要是可以序列化的类型

哪种类型可以序列化?根据unity文档:

有[Serializable]属性的自定义非抽象类

有[Serializable]属性的自定义结构体(unity4.5新增)

来自UntiyEngine.Object的对象引用

原始数据类型(int,float,double,bool,string等等)

可序列化的数组Array字段类型

可序列化的泛型列表List字段类型

一个很常见的数据结构不可被序列化:Dictionaries,即使把它们声明为公有并且有[SerializeField]属性。所以在开发游戏时记住这点。

好了,这里信息量有些大,所以将它们分解为简单的代码示例。

Examples

Let’s take the following code (MyBehaviour.cs) as an example:

作为示例看下边的代码(MyBehaviour.cs)):

[C#]纯文本查看 复制代码

using UnityEngine;

public class MyBehaviour : MonoBehaviour

{

[SerializeField] private int x = 3;

[SerializeField] private float y = 5.6f;

public float pi = 3.1415f;

private int mySecret = 42;

public static int myStatic = 10;

public const int myConst = 22;

public readonly int myReadOnly = 99;

public int MyProperty { get { return 100; } }

}

The only fields that are serialized are“x”,“y”and“pi”because they are not static, const, readonly, a property or private with no [SerializeField] attribute. One way to show this is by taking a look at the script’s inspector, which only shows us serialized fields (that can come handy):

仅有的被序列化的字段是“x”,“y” 和 “pi”,因为它们不是静态、常量、只读、没有[SerializeField]属性的私有变量。显示这个的方式之一是看一下只显示序列化字段的脚本的检视面板。

But there is a better way to show that the other fields were not serialized: by cloning the object. Remember I told you that the Instantiate method uses the Unity serialization process? So let’s test it by adding the following method to our script:

不过有一个更好的途径来显示没有序列化的其他字段:克隆对象。还记得我曾经说的实例化方法使用unity序列化过程吗?所以将下面的方法添加到脚本中来验证一下:

[C#]纯文本查看 复制代码

private void Start()

{

Debug.Log(“Pi:“+ pi +“. MySecret:“+ x +“. MyStatic:“+ myStatic);

}

private void Update()

{

if (Input.GetMouseButtonDown(0))

{

pi =–4;

mySecret =–11;

myStatic = 13;

GameObject.Instantiate(gameObject);

}

}

This method should modify the current object and create another object in the scene when the mouse’s left button is pressed. A naive thought would be that since the second object is a clone of the first one, it should have the same value for“pi”,“mySecret”and any other field as the first object, right? Well, it does for“pi”, because it’s a public field (hence it’s serialized), but it doesn’t for“mySecret”: its value remains unchanged when the second Debug.Log() is executed:

这个脚本可以修改当前的对象,并且当鼠标左键按下时可以在场景中创建另外一个对象。天真的认为既然第二个对象是第一个对象的克隆体,它的“pi”,“mySecret”或任何其他字段应该有和第一个对象相同的值,对吧?好了,对“pi”来说是这样的,因为它是一个公有字段(因此可以被序列化),不过对于“mySecret”来说不是的:当第二个Debug.Log()执行时它的值是保持不变的:

The field“mySecret”can’t be serialized because it’s a private field with no [SerializeField] attribute (which is the only circumstance a private fields will be serialized*).

*: Private fields are serialized in some circumstances in the Unity Editor and that can lead us to some problems we will discuss later on the next article on the“Problems”session. (source)

“mySecret”字段不可以呗序列化,因为它是一个没有[SerializeField]属性(私有字段可以被序列化的唯一情况)的私有字段。

*:unity编辑器中在某些情况下私有字段可以被序列化,而且这样会导致一些问题,我们会在下一篇“Problems”讲解中讨论这些问题。

Curiously, the value of“myStatic”changes in both objects, but does that mean static fields are serializable? The answer is no. Even though its behavior leads us to conclude that, remember that static fields belong to the class, and not to an instance of it. That said, if we, per example, create a new object and add a MyBehaviour script to it in play mode (Using“GameObject> Create Empty”in the menu),“myStatic”will have the same value as the other objects, although it isn’t a copy of any other object. However, note that the“pi”variable has its original value.

奇怪的是,“myStatic”值在两个对象中都改变了,不过这是意味着静态字段可以序列化吗?答案是否定的。即使这个行为引导我们得出了这样的结论,记住静态字段属于类,不是一个实例。也就是说,如果根据实例创建一个新的游戏对象并在运行模式下添加MyBehaviour脚本(使用菜单中的 “GameObject> Create Empty”),“myStatic”会和其他对象有相同的值,即使它并不是其他任何对象的复制体。然而,注意“pi”这个变量有它自己的原始值。

This proves what the Unity documentation tells us about how can we make a field of a serializable type be serialized. This works with most Unity objects, including MonoBehaviours, but what if I don’t want to define a MonoBehaviour and I still want to create a Serializable type? In other words, how can I define a Serializable type?

这就证实了unity文档告诉大家的怎样使一个序列化类型的字段被序列化。这个对于大多数unity对象都可以用,包括MonoBehaviours,但是如果不想定义MonoBehaviour却仍然想创建一个序列化类型呢?换句话说,要怎样定义一个序列化类型?

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 227,123评论 6 528
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 97,850评论 3 412
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 174,839评论 0 373
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 62,389评论 1 308
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 71,183评论 6 405
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 54,717评论 1 320
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 42,797评论 3 436
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 41,951评论 0 285
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 48,459评论 1 330
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 40,431评论 3 354
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 42,573评论 1 365
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 38,123评论 5 355
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 43,823评论 3 344
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 34,220评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 35,475评论 1 281
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 51,155评论 3 387
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 47,560评论 2 370

推荐阅读更多精彩内容