Unity3D 序列化机制:引擎内的应用场景和基本原理

135 阅读4分钟

前言

Unity3D 的序列化机制是其核心功能之一,用于在编辑器和运行时之间持久化数据、管理场景状态、处理预制体(Prefab)以及实现跨平台兼容性。以下是其应用场景和基本原理的详细解析:

对惹,这里有一个游戏开发交流小组 ,希望大家可以点击进来一起交流一下开发经验呀!

一、应用场景

  1. 场景(Scene)与预制体(Prefab)的保存与加载
  • Unity 使用序列化将场景中的 GameObject、组件(Component)及其属性保存为文本或二进制格式(如 .unity 场景文件或 .prefab 文件)。

  • 预制体的实例化和修改(如覆盖属性)依赖序列化机制。

  • Inspector 面板的编辑

  • 在编辑器中,组件的公有字段(或标记了 [SerializeField] 的私有字段)通过序列化机制暴露到 Inspector 面板,修改后的值会被序列化保存。

  • ScriptableObject 数据持久化

  • ScriptableObject 的数据通过序列化存储为 .asset 文件,适用于游戏配置(如技能、物品属性)。

  • 资源热更新与跨平台兼容

  • AssetBundle 中的资源(如材质、动画)通过序列化实现跨平台兼容,确保不同平台加载时数据格式正确。

  • 运行时状态持久化

  • 游戏存档(如玩家进度、物品栏)可通过序列化(如 JsonUtility 或 BinaryFormatter)保存到本地文件。

二、基本原理

1. 序列化的条件

Unity 的序列化遵循以下规则:

  • 自动序列化的字段

    • public 字段(除非标记 [NonSerialized])。
    • 标记了 [SerializeField] 的私有/受保护字段。
  • 不序列化的字段

    • 属性(Property)、静态字段、未标记 [SerializeField] 的私有字段。
    • 标记了 [NonSerialized] 的字段。

2. 序列化流程

  • 编辑器序列化

    • 当场景或预制体保存时,Unity 将 GameObject 的层级结构和组件属性转换为 YAML 格式文本(可读性高)。
    • 示例:一个 Transform 组件的序列化结果:
Transform:
  m_ObjectHideFlags: 0
  m_Position: {x: 0, y: 0, z: 0}
  m_Rotation: {x: 0, y: 0, z: 0, w: 1}
  • 运行时序列化

    • 使用 JsonUtility.ToJson() 或 BinaryFormatter 将对象转换为字符串或二进制数据。

3. 序列化深度

  • Unity 支持深度序列化,递归处理对象及其子属性。

  • 例外

    • 引用类型(如 UnityEngine.Object 派生类)会被序列化为元数据(如 GUID 和文件ID),而非完整对象。
    • 循环引用可能导致序列化失败。

4. 自定义序列化

通过接口 ISerializationCallbackReceiver,开发者可以在序列化前后执行逻辑:

public class CustomData : MonoBehaviour, ISerializationCallbackReceiver
{
    public Dictionary<string, int> stats = new Dictionary<string, int>();

    // 序列化前将 Dictionary 转换为 List
    [SerializeField] private List<string> _keys;
    [SerializeField] private List<int> _values;

    public void OnBeforeSerialize()
    {
        _keys = new List<string>(stats.Keys);
        _values = new List<int>(stats.Values);
    }

    public void OnAfterDeserialize()
    {
        stats = new Dictionary<string, int>();
        for (int i = 0; i < _keys.Count; i++)
            stats.Add(_keys[i], _values[i]);
    }
}

三、技术细节与注意事项

  1. 版本兼容性
  • 修改类结构(如删除字段)可能导致反序列化失败,旧数据可能丢失。

  • 通过 [FormerlySerializedAs("oldFieldName")] 标记字段重命名,兼容旧数据。

  • 性能优化

  • 避免频繁序列化大型数据结构(如长列表),尤其在移动端。

  • 使用 [Serializable] 标记自定义结构体或类以支持序列化。

  • 不可序列化的类型

  • Unity 无法序列化接口(interface)、委托(delegate)或非 UnityEngine.Object 派生类。

  • 解决方法:将接口转换为具体类,或使用 ScriptableObject 封装。

  • Prefab 差异序列化

  • 预制体实例的属性覆盖(如修改 Transform 的位置)通过序列化差异实现,保存为“覆盖”数据而非完整副本。

四、调试与工具

  1. 查看序列化数据
  • 在 Unity 编辑器中选择 Assets > Open C# Project,查看 .meta 文件或 YAML 格式的预制体/场景文件。

  • 序列化检查工具

  • 使用 UnityEditor.Serialization 命名空间中的工具(如 SerializedObject 和 SerializedProperty)在 Editor 脚本中调试序列化数据。

五、总结

Unity 的序列化机制是其数据驱动的核心,理解其规则和限制能帮助开发者:

  • 避免数据丢失(如字段未正确序列化)。

  • 优化资源管理(如合理使用 ScriptableObject)。

  • 实现灵活的自定义数据持久化方案。

更多教学视频

Unity3D​www.bycwedu.com/promotion_channels/2146264125