unity 序列化那些事,支持Dictionary序列化

这篇具有很好参考价值的文章主要介绍了unity 序列化那些事,支持Dictionary序列化。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

一、普通类型和UnityEngine空间类型序列化

二、数组、list的序列化

三、自定义类的序列化支持

 四、自定义asset

五、在inspector面板中支持Dictionary序列化

1、在MonoBehaviour中实现Dictionary序列化

 2、自定义property,让其在inpsector能够显示

3、MonoBehaviour脚本中Dictionary字典的测试

 4、asset中脚本对字典Dictionary的支持

1)下载OdinSerializer 序列化插件

2)定义序列化类


        unity中的inspector面板支持list,但是有时候我们需要Dictionary,尤其是我们需要通过asset资源与ScriptableObject脚本一起实现序列化时更是需要如此。如:技能需要通过id来确定访问单个技能数据,那必须满足key和Value的数据结构。

由于unity并不是原生的支持对字典的序列化,这件简述了unity关于序列化与及自定义类的序列化的方法,同时实现在inspector面板中字典序列化问题,以及asset资产中实现序列化 Dictionary的方法。在实际运用中我们可以通过OdinSerializer 的的Serialize插件配合使用来实现我们我想要的效果。

一、普通类型和UnityEngine空间类型序列化

对于普通的MonoBehaviour对象常用public数据类型是支持直接序列化的,如果是namespace UnityEngine下的对象都可以被序列化

unity 序列化那些事,支持Dictionary序列化

在inspector面板下,我们看到如果是基础类型和UnityEngine命名空间下类型,可以直接序列化。

unity 序列化那些事,支持Dictionary序列化


 

二、数组、list的序列化

在实际过程中我们往往需要数组或列表序列化。unity对与能显示指定类型的容器可以序列化。对于Array容器因为其不知道它所定义的数据类型unity并没有提供直接支持,当然字典Dictionary无法直接支持。

定义一个list<int>链表和int[]的原始数值

unity 序列化那些事,支持Dictionary序列化

inspector面板值 

unity 序列化那些事,支持Dictionary序列化


三、自定义类的序列化支持

我们有时并不满足只有基础类型的序列化,如果对自定义类进行序列化呢?这时候需要用到两个

attribute。在定义类的时候,需要Serializable和SerializeField配合使用。在定义类的时候添加Serializable属性,Serializable是作用类在,定义类成员变量时需要SerializeField,,SerializeField是作用字段

定义序列化类

unity 序列化那些事,支持Dictionary序列化

看下面板值 

unity 序列化那些事,支持Dictionary序列化

 我们前面讲过list和[]链表和数组类型的时候,基础类型是直接支持的,通过Serializable对类属性定义,并不需要SerializeField

如图:

定义自定义类容器

unity 序列化那些事,支持Dictionary序列化

ipspector面板的显示值 

 unity 序列化那些事,支持Dictionary序列化


 四、自定义asset

我们想不依赖MonoBehaviour类做序列化,只是想做纯数据的的资源,比如技能数据或这角色数据等。unity通过ScriptableObject该类来我们提供了实现的方法。CreateAssetMenu提供给我们一个创建菜单的属性,menuName是菜单名,fileName是文件名称

using UnityEngine;
using System;

[CreateAssetMenu(menuName = "Config/" + "技能数据", fileName = nameof(SkillData))]
public class SkillData : ScriptableObject
{

    public int id;
    public string name;

    public Effect effect;

}

[Serializable]
public class Effect
{
    public int type;
    public float beginTime;
    public float durationTime;
}

config/技能数据 下创建相对与SkillData类的asset.

操作步骤如下:Assets目录下找到你想要目录,点击右键,会弹出如下菜单:

unity 序列化那些事,支持Dictionary序列化

创建出SkillData.asset资源

unity 序列化那些事,支持Dictionary序列化


五、在inspector面板中支持Dictionary序列化

        总体设计思路是通过list实现对Dictionary的支持,由于Unity的inpsector面板中并不直接支持字典,所以我们还需要自定义Property,通过CustomPropertyDrawer属性来实现

1、在MonoBehaviour中实现Dictionary序列化

定义SerializableDictionary类,并继承IDictionary接口,重写该IDictionary接口函数

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public class SerializableDictionary { }

[Serializable]
public class SerializableDictionary<TKey, TValue> :
    SerializableDictionary,
    ISerializationCallbackReceiver,
    IDictionary<TKey, TValue>
{
    [SerializeField] private List<SerializableKeyValuePair> list = new List<SerializableKeyValuePair>();

    [Serializable]
    private struct SerializableKeyValuePair
    {
        public TKey Key;
        public TValue Value;

        public SerializableKeyValuePair(TKey key, TValue value)
        {
            Key = key;
            Value = value;
        }
    }

    private Dictionary<TKey, int> KeyPositions => _keyPositions.Value;
    private Lazy<Dictionary<TKey, int>> _keyPositions;

    public SerializableDictionary()
    {
        _keyPositions = new Lazy<Dictionary<TKey, int>>(MakeKeyPositions);
    }

    private Dictionary<TKey, int> MakeKeyPositions()
    {
        var dictionary = new Dictionary<TKey, int>(list.Count);
        for (var i = 0; i < list.Count; i++)
        {
            dictionary[list[i].Key] = i;
        }
        return dictionary;
    }

    public void OnBeforeSerialize() { }

    public void OnAfterDeserialize()
    {
        _keyPositions = new Lazy<Dictionary<TKey, int>>(MakeKeyPositions);
    }

    #region IDictionary<TKey, TValue>

    public TValue this[TKey key]
    {
        get => list[KeyPositions[key]].Value;
        set
        {
            var pair = new SerializableKeyValuePair(key, value);
            if (KeyPositions.ContainsKey(key))
            {
                list[KeyPositions[key]] = pair;
            }
            else
            {
                KeyPositions[key] = list.Count;
                list.Add(pair);
            }
        }
    }

    public ICollection<TKey> Keys => list.Select(tuple => tuple.Key).ToArray();
    public ICollection<TValue> Values => list.Select(tuple => tuple.Value).ToArray();

    public void Add(TKey key, TValue value)
    {
        if (KeyPositions.ContainsKey(key))
            throw new ArgumentException("An element with the same key already exists in the dictionary.");
        else
        {
            KeyPositions[key] = list.Count;
            list.Add(new SerializableKeyValuePair(key, value));
        }
    }

    public bool ContainsKey(TKey key) => KeyPositions.ContainsKey(key);

    public bool Remove(TKey key)
    {
        if (KeyPositions.TryGetValue(key, out var index))
        {
            KeyPositions.Remove(key);

            list.RemoveAt(index);
            for (var i = index; i < list.Count; i++)
                KeyPositions[list[i].Key] = i;

            return true;
        }
        else
            return false;
    }

    public bool TryGetValue(TKey key, out TValue value)
    {
        if (KeyPositions.TryGetValue(key, out var index))
        {
            value = list[index].Value;
            return true;
        }
        else
        {
            value = default;
            return false;
        }
    }

    #endregion

    #region ICollection <KeyValuePair<TKey, TValue>>

    public int Count => list.Count;
    public bool IsReadOnly => false;

    public void Add(KeyValuePair<TKey, TValue> kvp) => Add(kvp.Key, kvp.Value);

    public void Clear() => list.Clear();
    public bool Contains(KeyValuePair<TKey, TValue> kvp) => KeyPositions.ContainsKey(kvp.Key);

    public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
    {
        var numKeys = list.Count;
        if (array.Length - arrayIndex < numKeys)
            throw new ArgumentException("arrayIndex");
        for (var i = 0; i < numKeys; i++, arrayIndex++)
        {
            var entry = list[i];
            array[arrayIndex] = new KeyValuePair<TKey, TValue>(entry.Key, entry.Value);
        }
    }

    public bool Remove(KeyValuePair<TKey, TValue> kvp) => Remove(kvp.Key);

    #endregion

    #region IEnumerable <KeyValuePair<TKey, TValue>>

    public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
    {
        return list.Select(ToKeyValuePair).GetEnumerator();


    }
    static KeyValuePair<TKey, TValue> ToKeyValuePair(SerializableKeyValuePair skvp)
    {
        return new KeyValuePair<TKey, TValue>(skvp.Key, skvp.Value);
    }

    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();

    #endregion
}

 2、自定义property,让其在inpsector能够显示

在Editor目录下创建文件SerializableDictionaryDrawer,利用CustomPropertyDrawer属性创建

自定义Inpsector的显示内容

代码如下:

using UnityEditor;
using UnityEngine;

[CustomPropertyDrawer(typeof(SerializableDictionary), true)]
public class SerializableDictionaryDrawer : PropertyDrawer
{
    private SerializedProperty listProperty;

    private SerializedProperty getListProperty(SerializedProperty property)
    {
        if (listProperty == null)
            listProperty = property.FindPropertyRelative("list");

        return listProperty;

    }

    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        EditorGUI.PropertyField(position, getListProperty(property), label, true);
    }

    public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
    {
        return EditorGUI.GetPropertyHeight(getListProperty(property), true);
    }
}

3、MonoBehaviour脚本中Dictionary字典的测试

 unity 序列化那些事,支持Dictionary序列化

 4、asset中脚本对字典Dictionary的支持

如果我们想对asset资产文件同样对Dictionary支持,我这里通过OdinSerializer插件来实现,这里分享一个免费OdinSerializer插件。

1)下载OdinSerializer 序列化插件

                下载OdinSerializer

 unity 序列化那些事,支持Dictionary序列化

 

网络有点慢,耐心等待。

注意:命名空间需要自己定义,不然它会使用插件默认的 Sirenix命名空间,会报错。

2)定义序列化类

该类继承OdinSerializer插件中SerializedScriptableObject类

//创建测试Asset数据菜单
[CreateAssetMenu(menuName = "Config/" + "测试Asset数据", fileName = nameof(TestAssetData ))]

 public class TestAssetData : SerializedScriptableObject
 {
    public SerializableDictionary<int, int> data = new SerializableDictionary<int, int>();

 }

 至此,该篇所有内容完成文章来源地址https://www.toymoban.com/news/detail-503527.html

到了这里,关于unity 序列化那些事,支持Dictionary序列化的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Unity基于Google Protobuf序列化和反序列化小案例

    1.协议定义,简单实现传玩家的2D坐标    2.在Unity的Assets目录下创建一个Plugins文件夹(必须这样命名),此文件专门存放扩展文件, 再新建文件夹BaseInfolibrary,将Google.Protobuf.dll拖入  3.新建一个Test.cs脚本  脚本中引入命名空间 代码改进:通用序列化模板(只用来序列化Message)

    2024年02月15日
    浏览(33)
  • Unity序列化

    Unity 的序列化是作用于 C# 类的字段 而非属性。 序列化规则 对于需要被序列化的字段,需要遵守一些规则 访问修饰符是 public ,或者具有 SerializeField 特性 非 static 非 const 可以被序列化的字段类型 基础数据结构( int , float , double , bool , string 等) 枚举(32 位 或 以下) 固定大

    2024年02月06日
    浏览(39)
  • Unity——脚本与序列化

    数据序列化有以下几个主要的应用场景和目的: 1. 持久化存储:序列化可以将对象或数据结构转换为字节序列,使得其可以被存储在磁盘上或数据库中。通过序列化,我们可以将应用程序中运行时的数据持久化保存,以便在后续运行时重新加载和使用。 2. 数据传输:序列化

    2024年01月18日
    浏览(40)
  • unity中,什么是序列化资源?

    好的,以下是序列化资源(Serialized Asset)的详细解释,包括介绍、方法和举例: 在Unity中,序列化资源是指将Unity场景或预制件中的对象及其属性保存到磁盘上的文件中,以便在将来将其还原为原始状态。序列化资源文件可以包括场景文件(.unity)和预制件文件(.prefab),它

    2024年02月10日
    浏览(39)
  • 在Unity中使用Protobuf进行序列化

    目录 1.介绍 1.1 什么是Protobuf 1.2 Protobuf和其他数据序列化方案对比 2.下载Protobuf 2.1 方案一 使用VS的Nuget包管理器进行安装(推荐) 2.1.1安装Protobuff包 2.1.2拷贝.dll文件 2.2 方案二 从Github下载并自己生成.dll 2.2.1 下载Probuff 2.2.2 VS打开解决方案 2.2.3 安装.NET SDK 2.2.4 生成.dll文件 3

    2024年04月12日
    浏览(48)
  • Unity XML3——XML序列化

    ​ 序列化:把对象转化为可传输的字节序列过程称为序列化,就是把想要存储的内容转换为字节序列用于存储或传递 ​ 反序列化:把字节序列还原为对象的过程称为反序列化,就是把存储或收到的字节序列信息解析读取出来使用 1.准备数据结构 2.进行序列化 XmlSerializer:用

    2024年02月15日
    浏览(34)
  • 【工具篇】SerializableDictionary字典序列化Unity面板显示

    目录 一:导入插件 二:创建目标字典类 三:生成数据  四:自定义配置数据 Unity本身对字典这种数据结构没有序列

    2024年02月15日
    浏览(35)
  • unity 通过 二维数组序列化 实现二维数组在编辑器面板查看和配置数据

    实现思路如下: 1、定义一个二维数组数据类 2、奖数据类标记为 Serializable  并实现 unity内置的  ISerializationCallbackReceiver接口,接口提供了序列化和反序列化方法,参见官方文档(文档中给出了字典的序列化方法):Unity - Scripting API: ISerializationCallbackReceiver 3、使用unity序列化

    2024年02月08日
    浏览(43)
  • Unity Image(RawImage) 实现按轴心放大缩小,序列化存储轴心信息,实现编译器窗口保存轴心

    工作时分配给我的要实现的功能,写的时候遇到挺多的坑的,在此记录一下 放大缩小的效果 2.编译器扩展窗口记录 1.打开WSC/保存图片轴心工具,在Image位置挂在需要保存轴心的图像,输出name作为key,并在Scene窗口中直接拖动轴心确定位置(不建议在Inspector中手动输入轴心修改

    2024年02月14日
    浏览(46)
  • 【序列化与反序列化】关于序列化与反序列化MessagePack的实践

    在进行序列化操作之前,我们还对系统进行压测,通过 jvisualvm 分析cpu,线程,垃圾回收情况等;运用火焰图 async-profiler 分析系统性能,找出程序中占用CPU资源时间最长的代码块。 代码放置GitHub:https://github.com/nateshao/leetcode/tree/main/source-code/src/main/java/com/nateshao/source/code/ser

    2024年02月11日
    浏览(55)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包