Unity3D 的序列化机制是其核心功能之一,用于在编辑器和运行时之间持久化数据、管理场景状态、处理预制体(Prefab)以及实现跨平台兼容性。以下是其应用场景和基本原理的详细解析:
对惹,这里有一个游戏开发交流小组,希望大家可以点击进来一起交流一下开发经验呀!
一、应用场景
场景(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]);
}
}
三、技术细节与注意事项
版本兼容性
修改类结构(如删除字段)可能导致反序列化失败,旧数据可能丢失。
通过 [FormerlySerializedAs("oldFieldName")] 标记字段重命名,兼容旧数据。
性能优化
避免频繁序列化大型数据结构(如长列表),尤其在移动端。
使用 [Serializable] 标记自定义结构体或类以支持序列化。
不可序列化的类型
Unity 无法序列化接口(interface)、委托(delegate)或非 UnityEngine.Object 派生类。
解决方法:将接口转换为具体类,或使用 ScriptableObject 封装。
Prefab 差异序列化
预制体实例的属性覆盖(如修改 Transform 的位置)通过序列化差异实现,保存为“覆盖”数据而非完整副本。
四、调试与工具
查看序列化数据
在 Unity 编辑器中选择 Assets > Open C# Project,查看 .meta 文件或 YAML 格式的预制体/场景文件。
序列化检查工具
使用 UnityEditor.Serialization 命名空间中的工具(如 SerializedObject 和 SerializedProperty)在 Editor 脚本中调试序列化数据。
五、总结
Unity 的序列化机制是其数据驱动的核心,理解其规则和限制能帮助开发者:
避免数据丢失(如字段未正确序列化)。
优化资源管理(如合理使用 ScriptableObject)。
实现灵活的自定义数据持久化方案。