【问题标题】:How to Serialize and Deserialize a Dictionary Containing Gameobject and a Vector2 in Unity如何在 Unity 中序列化和反序列化包含 Gameobject 和 Vector2 的字典
【发布时间】:2021-06-07 06:54:51
【问题描述】:

我正在为一个可以在统一编辑模式下编辑关卡的游戏制作关卡编辑器。它最终保存了进度,可以在游戏运行时加载回来,但事实证明你不能通过统一序列化 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();
 }

我怎样才能序列化这个字典?任何建议将不胜感激。

【问题讨论】:

    标签: c# xml unity3d serialization


    【解决方案1】:

    一般来说:You shouldn't use BinaryFormatter anymore


    您可以构建一个实现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;
    

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

    【讨论】:

    • 嗨,非常感谢@derHugo 的回答。它就像一种魅力,解决了我一段时间以来一直困扰的问题,我必须学习一门新东西。我非常感谢您为这个答案所做的努力。对我很重要。你是一颗宝石。非常感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-18
    相关资源
    最近更新 更多