Version: Unity 6.0 (6000.0)
语言 : 中文
自定义序列化
JSON 序列化

Unity 如何使用序列化

保存和加载

Unity 使用序列化技术从设备内存加载和保存场景资源AssetBundle。这包括保存在您自己的脚本 API 对象(如 MonoBehaviour 组件和 ScriptableObjects)中的数据。

Unity 编辑器中的许多功能都建立在核心序列化系统之上。对于序列化要特别注意的两点是 Inspector 窗口和热重载。

Inspector 窗口

Inspector 窗口显示被检查对象的序列化字段的值。当更改 Inspector 中的值时,Inspector 会更新序列化数据并触发反序列化,以更新检查的对象。

这对于内置的 Unity 对象以及脚本对象(如 MonoBehaviour 派生类)也适用。

在 Inspector 窗口中查看或更改值时,Unity 不会调用任何 C# 属性的 getter 和 setter。相反,Unity 会直接访问序列化的后备字段。

热重载

脚本代码的热重载是在资源数据库刷新过程中执行的。它指的是在编辑器运行时直接重新加载和应用代码更改,而无需重新启动编辑器。有关更多信息,请参阅刷新资源数据库热重载

注意:热重载是一种特殊的序列化情况。与 Unity 中的其他序列化情况不同,私有字段在重新加载时会默认序列化,即使它们没有 SerializeField 属性也是如此。

重新加载脚本时:

  1. Unity 会在所有加载的脚本中序列化并存储所有变量。
  2. Unity 会将它们恢复为序列化前的原始值。
    • Unity 会恢复满足序列化要求的所有变量(包括私有变量),即使变量没有 [SerializeField] 属性也是如此。在某些情况下,需要防止 Unity 恢复私有变量:例如,如果您希望从脚本重新加载后引用为 null。在这种情况下,请使用 [field: NonSerialized] 属性。
    • Unity 绝不会恢复静态变量,因此对于 Unity 重新加载脚本后需要保留的状态,不要使用静态变量,因为会在重载过程中被丢弃。

预制件

预制件是一个或多个游戏对象组件的序列化的数据。预制件实例包含对预制件源及其一系列修改的引用。这些修改是 Unity 为了创建特定预制件实例而需要对预制件源进行的操作。

只有在 Unity 编辑器中编辑项目时,预制件实例才存在。Unity 编辑器从两组序列化数据(预制件源和预制件实例的修改)进行游戏对象的实例化。

实例化

对场景中存在的任何对象(例如预制件或游戏对象)调用 Instantiate 时:

  1. Unity 都会对其进行序列化。在运行时和在 Editor 中都是如此。从 UnityEngine.Object 派生的一切均可被 Unity 序列化。
  2. Unity 创建一个新的游戏对象并将数据反序列化到新的游戏对象上。
  3. Unity 在另一个不同的变体中运行相同的序列化代码,以报告其引用的其他 UnityEngine.Objects。它会检查所有引用的 UnityEngine.Objects 以确定它们是否是 Unity 要实例化的数据的一部分。如果引用指向外部,例如纹理,则 Unity 会保持该引用不变。如果引用指向内部,例如子游戏对象,则 Unity 会修补对相应副本的引用。

卸载未使用的资源

EditorUtility.UnloadUnusedAssetsImmediate 是本机 Unity 垃圾回收器,相较于标准 C# 垃圾回收器有不同的作用。该垃圾回收器在您加载场景之后运行,检查其不再引用的对象(如纹理),并安全卸载它们。本机 Unity 垃圾回收器在一个变体中运行序列化程序,而在此变体中,对象会报告对外部 UnityEngine.Objects 的所有引用。这就是一个场景中使用的纹理,在下一个场景中,垃圾回收器在卸载它们的方式。

编辑器和运行时序列化之间的差异

大多数序列化发生在编辑器中而反序列化则在运行时进行。Unity 仅在编辑器中序列化某些功能,而在编辑器和运行时都可以序列化其他功能:

功能 Editor 运行时
二进制格式的资源 支持读/写 支持读
YAML 格式的资源 支持读/写 不支持
保存场景、预制件和其他资源 支持,除非处于播放模式 不支持
使用 JsonUtility 进行单个对象的序列化 JsonUtility 提供读/写支持。

使用 EditorJsonUtility 支持其他类型的对象
JsonUtility 提供读/写支持
SerializeReference 受支持 受支持
ISerializationCallbackReceiver 受支持 受支持
FormerlySerializedAs 受支持 不支持

对象可以具有只有编辑器能序列化的其他字段,例如在 UNITY_EDITOR 脚本符号中声明字段时:

public class SerializeRules : MonoBehaviour
{
#if UNITY_EDITOR
public int m_intEditorOnly;
#endif
}

在上一个示例中,m_intEditorOnly 字段仅在编辑器中序列化,未包含在构建中。这使您能够通过在构建中省略仅在编辑器中需要的数据来节省内存。任何使用该字段的代码也需要进行条件编译,例如在 #if UNITY_EDITOR 代码块中,以便该类可以在构建时编译。

编辑器不支持具有 Unity 仅在运行时序列化的字段的对象(例如,在 UNITY_STANDALONE 指令中声明字段时)。

其他资源

自定义序列化
JSON 序列化