在 Unity 中,序列化是指将对象数据转换为可存储或传输的格式,以便在需要时能够恢复这些数据。 其反序列化则是将序列化后的数据转换回对象的过程。Unity 的一些内置功能(如保存和加载、Inspector 窗口、实例化和预制件等)都需要使用序列化。
Unity 中可序列化的对象需要满足一定条件:
- 该对象必须是非 static、非 const、非 readonly,且为 public 或者具有SerializeField属性;
- 可序列化的字段类型包括原始数据类型(如 int、float、double、bool、string 等)、枚举类型、具有Serializable属性的自定义结构体、某些 Unity 内置类型(如 Vector2、Vector3、Vector4、Rect、Quaternion、Matrix4x4、Color、Color32、LayerMask、AnimationCurve、Gradient、RectOffset、GUIStyle 等)、可自定义序列化类(该类必须具有Serializable属性,且非静态、非抽象、非泛型,可继承自泛型类),以及上述类型的数组、线性表List<T>。
Unity 不能直接序列化一些类型,例如属性、树结构、泛型、字典、高维数组、委托等。对于这些不被支持的对象及序列化的实现方法如下:
- 对于字典,可以将 key 和 value 各自存储成 list,运行时使用字典,序列化时使用数组;
- 对于高维数组,可将其低维化,即底层采用一维数组来替代;
- 对于泛型类,用一个新类将其封装并用(Serializable)修饰新类;
- 对于不带返回值的委托,可以用UnityEvent来序列化;
- 对于更复杂的情况,例如树结构,需实现ISerializationCallbackReceiver接口,在该接口的OnBeforeSerialize方法中处理树结构的序列化,在OnAfterDeserialize方法中进行反序列化后的处理。
以下是一个使用ISerializationCallbackReceiver接口处理字典序列化的示例代码:
using UnityEngine;
using System;
using System.Collections.Generic;
public class SerializationCallbackScript : MonoBehaviour, ISerializationCallbackReceiver
{
public List<int> _keys = new List<int> { 3, 4, 5 };
public List<string> _values = new List<string> { "i", "love", "unity" };
// Unity 不知道如何序列化字典
public Dictionary<int, string> _mydictionary = new Dictionary<int, string>();
// 在序列化之前被调用
public void OnBeforeSerialize()
{
_keys.Clear();
_values.Clear();
foreach (var kvp in _mydictionary)
{
_keys.Add(kvp.Key);
_values.Add(kvp.Value);
}
}
// 在反序列化之后被调用
public void OnAfterDeserialize()
{
_mydictionary = new Dictionary<int, string>();
for (int i = 0; i!= Math.Min(_keys.Count, _values.Count); i++)
_mydictionary.Add(_keys[i], _values[i]);
}
void OnGUI()
{
foreach (var kvp in _mydictionary)
GUILayout.Label("key: " + kvp.Key + " value: " + kvp.Value);
}
}
Unity 提供了多种方法来实现序列化,包括使用内置的 UnityEngine.JsonUtility、System.Serializable、BinaryFormatter 以及第三方库如 Newtonsoft.Json。以下是一些常见的序列化方法及其示例:
1. 使用 System.Serializable
Unity 的 System.Serializable 特性可以使类和结构体的实例在 Unity Inspector 中可见,并且能够进行序列化和反序列化。
示例代码
[System.Serializable]
public class PlayerData
{
public string playerName;
public int playerScore;
}
2. 使用 JsonUtility
JsonUtility 是 Unity 提供的一个简单且高效的 JSON 序列化工具,适用于简单的对象序列化和反序列化。
示例代码
using UnityEngine;
[System.Serializable]
public class PlayerData
{
public string playerName;
public int playerScore;
}
public class JsonExample : MonoBehaviour
{
void Start()
{
PlayerData player = new PlayerData { playerName = "John", playerScore = 100 };
// 序列化为 JSON
string json = JsonUtility.ToJson(player);
Debug.Log("Serialized JSON: " + json);
// 反序列化为对象
PlayerData deserializedPlayer = JsonUtility.FromJson<PlayerData>(json);
Debug.Log("Deserialized Player Name: " + deserializedPlayer.playerName);
}
}
3. 使用 BinaryFormatter
BinaryFormatter 适用于需要将对象序列化为二进制数据的情况。
示例代码
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using UnityEngine;
[System.Serializable]
public class PlayerData
{
public string playerName;
public int playerScore;
}
public class BinaryExample : MonoBehaviour
{
void Start()
{
PlayerData player = new PlayerData { playerName = "John", playerScore = 100 };
string path = Application.persistentDataPath + "/playerdata.dat";
// 序列化为二进制
BinaryFormatter bf = new BinaryFormatter();
FileStream file = File.Create(path);
bf.Serialize(file, player);
file.Close();
Debug.Log("Data saved to " + path);
// 反序列化为对象
if (File.Exists(path))
{
file = File.Open(path, FileMode.Open);
PlayerData deserializedPlayer = (PlayerData)bf.Deserialize(file);
file.Close();
Debug.Log("Deserialized Player Name: " + deserializedPlayer.playerName);
}
}
}
4. 使用 Newtonsoft.Json
Newtonsoft.Json(又名 Json.NET)是一个功能强大且流行的 JSON 库,适用于需要高级 JSON 序列化功能的情况。需要先安装 Newtonsoft.Json 包。
安装步骤
- 在 Unity 中,打开 Window > Package Manager。
- 点击左上角的 + 号,选择 Add package from git URL。
- 输入 https://github.com/jilleJr/Newtonsoft.Json-for-Unity.git,然后点击 Add。
示例代码
using Newtonsoft.Json;
using UnityEngine;
[System.Serializable]
Public class PlayerData
{
public string playerName;
public int playerScore;
}
public class NewtonsoftJsonExample : MonoBehaviour
{
void Start()
{
PlayerData player = new PlayerData { playerName = "John", playerScore = 100 };
// 序列化为 JSON
string json = JsonConvert.SerializeObject(player);
Debug.Log("Serialized JSON: " + json);
// 反序列化为对象
PlayerData deserializedPlayer = JsonConvert.DeserializeObject<PlayerData>(json);
Debug.Log("Deserialized Player Name: " + deserializedPlayer.playerName);
}
}
序列化注意事项
- 字段和属性:确保需要序列化的字段是公共的或标记为 [SerializeField]。
- 循环引用:避免在对象中使用循环引用,否则会导致序列化失败。
- 版本兼容性:在更新对象结构时,考虑如何处理旧版本的数据,避免反序列化失败。
通过以上方法,你可以在 Unity 中实现对象的序列化和反序列化,根据具体需求选择合适的工具和方法。