繁体   English   中英

如何在 Unity 中序列化和反序列化包含 Gameobject 和 Vector2 的字典

[英]How to Serialize and Deserialize a Dictionary Containing Gameobject and a Vector2 in Unity

我正在为一个可以在统一的编辑模式下编辑关卡的游戏制作关卡编辑器。 它最终保存了可以在游戏运行时加载回来的进度,但事实证明你不能通过统一序列化 Unity 的 Gameobject 或任何自定义 C# object(即使它这么说)。 我能够序列化大部分内容,但坚持使用一个字典 object。

现在,问题来了。

[HideInInspector] public Dictionary<GameObject, Vector2> occupants;

这包含一个 GameObject 和一个 Vector2 的字典(向量 2 是 2d 网格中的 position,而不是 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接口的包装器 class。 在他们的示例中,甚至几乎有您的确切用例!

稍作修改的解决方案可能如下所示

[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;

并像Dictionary<GameObject, Vector2>一样使用它(我的意思是AddRemoveClearforeach等)。


在这里,它正在发挥作用。 我只是使用了这个简单的测试脚本

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 个对象的位置。
  • 然后我将它们移动到其他地方并保存场景
  • 我卸载场景并创建一个新的空场景
  • 我加载回原始场景
  • 点击应用后的结果所有对象都回到 position 中,这意味着字典已成功(反)序列化;)

在此处输入图像描述

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM