Unity 如何使用序列化
More details about how serialization works in Unity.
阅读时间7 分钟最后更新于 1 个月前
保存和加载
Unity 使用序列化技术从设备内存加载和保存场景、资源和 AssetBundle。这包括保存在您自己的脚本 API 对象(如 MonoBehaviour 组件和 ScriptableObjects)中的数据。
Unity 编辑器中的许多功能都建立在核心序列化系统之上。对于序列化要特别注意的两点是 Inspector 窗口和热重载。
Inspector 窗口
Inspector 窗口显示被检查对象的序列化字段的值。当更改 Inspector 中的值时,Inspector 会更新序列化数据并触发反序列化,以更新检查的对象。
这对于内置的 Unity 对象以及脚本对象(如 MonoBehaviour 派生类)也适用。
在 Inspector 窗口中查看或更改值时,Unity 不会调用任何 C# 属性的 getter 和 setter。相反,Unity 会直接访问序列化的后备字段。
热重载
注意:热重载是一种特殊的序列化情况。与 Unity 中的其他序列化情况不同,私有字段在重新加载时会默认序列化,即使它们没有 SerializeField 属性也是如此。
重新加载脚本时:
-
Unity 会在所有加载的脚本中序列化并存储所有变量。
-
Unity 会将它们恢复为序列化前的原始值。
- Unity 会恢复满足序列化要求的所有变量(包括私有变量),即使变量没有 属性也是如此。在某些情况下,需要防止 Unity 恢复私有变量:例如,如果您希望从脚本重新加载后引用为 null。在这种情况下,请使用
[SerializeField]属性。[field: NonSerialized] - Unity 绝不会恢复静态变量,因此对于 Unity 重新加载脚本后需要保留的状态,不要使用静态变量,因为会在重载过程中被丢弃。
- Unity 会恢复满足序列化要求的所有变量(包括私有变量),即使变量没有
预制件
只有在 Unity 编辑器中编辑项目时,预制件实例才存在。Unity 编辑器从两组序列化数据(预制件源和预制件实例的修改)进行游戏对象的实例化。
实例化
对场景中存在的任何对象(例如预制件或游戏对象)调用 时:
Instantiate- Unity 都会对其进行序列化。在运行时和在 Editor 中都是如此。从 派生的一切均可被 Unity 序列化。
UnityEngine.Object - Unity 创建一个新的游戏对象并将数据反序列化到新的游戏对象上。
- Unity 在另一个不同的变体中运行相同的序列化代码,以报告其引用的其他 。它会检查所有引用的
UnityEngine.Objects以确定它们是否是 Unity 要实例化的数据的一部分。如果引用指向外部,例如纹理,则 Unity 会保持该引用不变。如果引用指向内部,例如子游戏对象,则 Unity 会修补对相应副本的引用。UnityEngine.Objects
卸载未使用的资源
EditorUtility.UnloadUnusedAssetsImmediateUnityEngine.Objects编辑器和运行时序列化之间的差异
大多数序列化发生在编辑器中而反序列化则在运行时进行。Unity 仅在编辑器中序列化某些功能,而在编辑器和运行时都可以序列化其他功能:
功能 | Editor | 运行时 |
|---|---|---|
| 二进制格式的资源 | 支持读/写 | 支持读 |
| YAML 格式的资源 | 支持读/写 | 不支持 |
| 保存场景、预制件和其他资源 | 支持,除非处于播放模式 | 不支持 |
| 使用 JsonUtility 进行单个对象的序列化 | JsonUtility 提供读/写支持。 使用 EditorJsonUtility 支持其他类型的对象 | JsonUtility 提供读/写支持 |
| SerializeReference | 受支持 | 受支持 |
| ISerializationCallbackReceiver | 受支持 | 受支持 |
| FormerlySerializedAs | 受支持 | 不支持 |
对象可以具有只有编辑器能序列化的其他字段,例如在 UNITY_EDITOR 脚本符号中声明字段时:
public class SerializeRules : MonoBehaviour{#if UNITY_EDITORpublic int m_intEditorOnly;#endif}
在上一个示例中, 字段仅在编辑器中序列化,未包含在构建中。这使您能够通过在构建中省略仅在编辑器中需要的数据来节省内存。任何使用该字段的代码也需要进行条件编译,例如在 代码块中,以便该类可以在构建时编译。
m_intEditorOnly#if UNITY_EDITOR编辑器不支持具有 Unity 仅在运行时序列化的字段的对象(例如,在 UNITY_STANDALONE 指令中声明字段时)。