c# - 如何在 Unity 中序列化和反序列化包含 Gameobject 和 Vector2 的字典
问题描述
我正在为一个可以在统一的编辑模式下编辑关卡的游戏制作关卡编辑器。它最终保存了进度,可以在游戏运行时加载回来,但事实证明你不能通过统一序列化 Unity 的 Gameobject 或任何自定义 C# 对象(即使它这么说)。我能够序列化大部分内容,但坚持使用一个 Dictionary 对象。
现在,问题来了。
[HideInInspector] public Dictionary<GameObject, Vector2> occupants;
这包含一个 GameObject 和一个 Vector2 的字典(Vector 2 是 2d 网格中的位置,而不是 2d 空间)。它们都不能通过正常方法序列化。
public static void SaveDataValues(DataValuesToSave dataValues, string level)
{
BinaryFormatter formatter = new BinaryFormatter();
string path = Application.persistentDataPath + level + ".dat";
FileStream stream = new FileStream(path, FileMode.Create);
DataValuesToSave data = dataValues;
formatter.Serialize(stream, data);
stream.Close();
}
我怎样才能序列化这个字典?任何建议,将不胜感激。
解决方案
总的来说:您根本不应该再BinaryFormatter
使用!
您可以构建一个实现ISerializationCallbackReceiver
接口的包装类。在他们的示例中,甚至几乎有您的确切用例!
稍作修改的解决方案可能如下所示
[Serializable]
public class YourDictionary: Dictionary<GameObject, Vector2>, ISerializationCallbackReceiver
{
[HideInInspector][SerializeField] private List<GameObject> _keys = new List<GameObject>();
[HideInInspector][SerializeField] private List<Vector2> _values = new List<Vector2>();
public void OnBeforeSerialize()
{
_keys.Clear();
_values.Clear();
foreach (var kvp in this)
{
_keys.Add(kvp.Key);
_values.Add(kvp.Value);
}
}
public void OnAfterDeserialize()
{
Clear();
for (var i = 0; i != Math.Min(_keys.Count, _values.Count); i++)
{
Add(_keys[i], _values[i]);
}
}
}
这样您就可以保留字典及其接口的全部功能,而只需在顶部添加序列化。
然后在您使用的其他脚本中
[HideInInspector] public YourDictionary occupants;
并像 a Dictionary<GameObject, Vector2>
(我的意思是Add
, Remove
, Clear
,foreach
等) 一样使用它。
在这里,它正在发挥作用。我只是使用了这个简单的测试脚本
public class NewBehaviourScript : MonoBehaviour
{
public GameObject obj;
[HideInInspector] public YourDictionary occupants;
[ContextMenu(nameof(Add))]
private void Add()
{
Vector2 vec = obj.transform.position;
occupants.Add(obj, vec);
}
[ContextMenu(nameof(Apply))]
private void Apply()
{
foreach (var kvp in occupants)
{
kvp.Key.transform.position = kvp.Value;
}
}
[ContextMenu(nameof(Remove))]
private void Remove()
{
occupants.Remove(obj);
}
}
现在可以愉快地为场景中的对象存储、删除和应用位置;)
- 我首先存储 4 个对象的位置。
- 然后我将它们移动到其他地方并保存场景
- 我卸载场景并创建一个新的空场景
- 我加载回原始场景
- 点击应用后的结果所有对象都回到原位,这意味着字典已成功(反)序列化;)
推荐阅读
- java - 如何获取注解上方的注解
- swift - 为什么 UItableview 对象上不显示文本
- excel - 在主工作簿中打开工作表并将其复制到某些工作表
- typescript - 由作为参数提供的回调的返回类型提供的函数的返回类型
- reactjs - Apache 配置允许直接导航到 React 的客户端 URL
- reactjs - 如何在 React 中更改 App 组件的状态
- sql - 无法使用 unnest 函数分隔多列值
- javascript - 我如何总是从 API 调用中选择最后一个 JSON 对象?
- scala - 无法使用用户名和密码创建 MQTT 流
- amazon-web-services - 如何诊断简单的 main.tf Terraform/AWS 错误?