前言
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]
的字段。
- 属性(Property)、静态字段、未标记
2. 序列化流程
- 编辑器序列化:
- 当场景或预制体保存时,Unity 将 GameObject 的层级结构和组件属性转换为 YAML 格式文本(可读性高)。
- 示例:一个 Transform 组件的序列化结果:
Transform:m_ObjectHideFlags: 0m_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)。
- 实现灵活的自定义数据持久化方案。
更多教学视频
Unity3Dwww.bycwedu.com/promotion_channels/2146264125