「Unity3D」属性面板(Inspector)上增删操作,序列化的Dictionary对象的k-v数值

news2024/11/25 9:33:52

Unity无法序列化Dictionary对象,可以通过实现ISerializationCallbackReceiver接口,来自定义实现,即:搞一个key list和一个value list分别存储dict的k-v,于是属性面板上就会显示,k-v的两个列表。

但这会有一个问题,就是在面板上,增删k-v会导致报错,因为——增加会复制最后一个key值导致重复,删除会导致k-v列表不对应。

解决方案是,在反序列化回调OnAfterDeserialize中,去处理k-v的增删,即:需要生成唯一的key值,以及同步k-v列表的数量,然后写入dict。

先看,自定义实现ISerializationCallbackReceiver接口的泛型Dictionary

[Serializable]
public abstract class SerializationDict<TKey, TValue> : Dictionary<TKey, TValue>, ISerializationCallbackReceiver
{
    [SerializeField]
    private List<TKey>   dictKeys   = new();
    [SerializeField]
    private List<TValue> dictValues = new();

    /// <summary>
    /// Gets unique temporary key for the Inspector add new item.
    /// </summary>
    public abstract TKey GetUniqueTmpKey(int keyIndex);


    /// <summary>
    /// Copies the Dict to the serialization KVs.
    /// </summary>
    public void OnBeforeSerialize()
    {
        this.dictKeys  .Clear();
        this.dictValues.Clear();

        foreach (var pair in this)
        {
            this.dictKeys  .Add(pair.Key);
            this.dictValues.Add(pair.Value);
        }
    }


    /// <summary>
    /// Copies the serialization KVs to the Dict.
    /// </summary>
    public void OnAfterDeserialize()
    {
        var keysCount   = this.dictKeys.Count;
        var valuesCount = this.dictValues.Count;
        var diff        = keysCount - valuesCount;

        if (diff > 0)
        {
            if (keysCount > this.Count)
            {
                // Inspector add new keys requires to add values
                for (var i = 0; i < diff; ++i)
                {
                    var keyIndex            = valuesCount + i;
                    this.dictKeys[keyIndex] = this.GetUniqueTmpKey(keyIndex);
                    this.dictValues.Add(default);
                }
            }
            else if (keysCount == this.Count)
            {
                // Inspector remove values requires to remove keys
                this.dictKeys.RemoveRange(keysCount - diff, diff);
                keysCount = this.dictKeys.Count;
            }
        }
        else if (diff < 0)
        {   
            if (keysCount < this.Count)
            {
                // Inspector remove keys
            }
            else if (keysCount == this.Count)
            {
                // Inspector add new values requires to add keys
                for (var i = diff; i < 0; ++i)
                {
                    this.dictKeys.Add(this.GetUniqueTmpKey(this.dictKeys.Count));
                }

                keysCount = this.dictKeys.Count;
            }
        }

        this.Clear();

        for (int i = 0; i < keysCount; i++)
        {
            this.Add(this.dictKeys[i], this.dictValues[i]);
            // this[this.dictKeys[i]] = this.dictValues[i];
        }
    }
}
  • OnAfterDeserialize是反序列化回调,面板操作k-v列表后执行,此时需要将k-v数值写入dict。
  • 由于是泛型key值,无法知道什么类型,所以需要给具体类去生成一个唯一key,即实现TKey GetUniqueTmpKey(int keyIndex)抽象方法。
  • 利用GetUniqueTmpKey的返回值,来填充面板增加的key值,就可以避免写入dict时的key重复。

再来看,一个具体的实现类。

[Serializable]
public class SerializationSpriteDict : SerializationDict<string, Sprite>
{
    public override string GetUniqueTmpKey(int keyIndex)
    {
        return "TmpKey" + keyIndex;
    }
}
  • 这个可序列化的Dictionary,是string-sprite的键值对。
  • 在这个类中,可以返回字符串的唯一key值。

最后,任意具体类型的Dictionary都可以,继承SerializationDict<TKey, TValue>,再提供生成唯一key值的方法实现,这样属性面板就可以增删,这个Dictionary了。

当然,增删的k-v值,都是临时的,有意义的数值需要手动去填充——也可以用代码去填充,再用面板去查看与修改。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2045652.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【鸿蒙基础系列】鸿蒙基础组件

&#x1f41f;作者简介&#xff1a;一名大三在校生&#xff0c;喜欢编程&#x1fab4; &#x1f421;&#x1f419;个人主页&#x1f947;&#xff1a;Aic山鱼 &#x1f420;WeChat&#xff1a;z7010cyy &#x1f988;系列专栏&#xff1a;&#x1f3de;️ 前端-JS基础专栏✨前…

stm32智能颜色送餐小车(红外光管避障)

大家好啊&#xff0c;我是情谊&#xff0c;今天我们来介绍一下我最近设计的stm32产品&#xff0c;我们在今年七月份的时候参加了光电设计大赛&#xff0c;我们小队使用的就是stm32的智能送餐小车&#xff0c;虽然止步于省赛&#xff0c;但是还是一次成长的经验吧&#xff0c;那…

Sql与Rce注入相关漏洞复现

目录 sqli-labs注入第38&#xff0c;48关 第38关&#xff08;单引号闭合&#xff09; ​编辑 第48关 (GET请求-基于错误-盲注-数字型-order by 排序 ​编辑 贷齐乐系统多处Sql注入漏洞 环境搭建 将贷齐乐源码放入phpstudy中的www目录下 在phpstudy上创建网站&#xff1…

DevEcoStudio对Gitee进行变基与合并

当尝试将本地分支的更改推送到远程仓库&#xff0c;但是远程仓库中的该分支已经有了您本地分支中没有的提交时&#xff0c;会出现这个提示。 具体来说&#xff0c;这个提示意味着&#xff1a; 推送被拒绝&#xff1a;不能直接将更改推送到远程仓库&#xff0c;因为远程仓库中…

WeNet模型学习笔记

WeNet是一个端到端语音识别模型&#xff0c;由于其优越的特性&#xff0c;成为近几年语音识别领域的热门模型。WeNet模型是一种CTC和attention结构的混合体&#xff0c;以Conformer或Transformer作为encoder&#xff0c;并使用attention decoder对CTC的输出进行重新打分(rescor…

微信小程序用 pinia数据化存储信息

import { defineStore } from pinia import { ref } from vue import type {LoginResult} from /types/member //定义 Store export const useMemberStore defineStore( member, () > { // 会员信息 const profile ref<LoginResult>() //保存会员信息&#xff0c…

MySQL数据库:详细安装与配置指南

目录 背景: 一.下载过程(MySQL数据库): 二.安装过程(MySQL数据库)&#xff1a; 三.验证MySQL是否安装成功 背景: MySQL 是一个流行的开源关系数据库管理(RDBMS)&#xff0c;由瑞典MySQL AB公司开发&#xff0c;后俩该公司被Sun Microsystems收购&#xff0c;Sun Microsyste…

el-table的多选功能

html&#xff1a; <el-table :data"list" row-key"id" selection-change"handleSelectionChange"><el-table-column type"selection" width"55"/> </el-table> js变量&#xff1a; data () {return {/…

日期类代码实现-C++

一、目标 通过前面对类和对象的介绍我们可以自己通过C代码初步实现一个简单的日期类。 实现的主要操作有&#xff1a; 1.日期类的构造函数 2.日期类的拷贝构造函数&#xff08;在头文件中实现&#xff09; 3.日期类的比较运算符重载 4.日期类的计算运算符重载 5.流插入运…

Python 爬数据案例 客户端服务端http请求 推荐 【进阶篇 2 】

网络爬虫数据原来这么简单&#xff01;&#xff01;&#xff01; 前面已经总结了关于python的面向对象继承多态的知识&#xff0c;这里主要是模块、读写文件、http请求网络数据以及如何获取网络数据知识。 网络爬虫是典型的应用程序&#xff0c;它的工作原理就是通过不断的请…

VBA语言専攻T3学员领取资料通知0817

T3学员领取资料通知0817 各位学员∶本周MF系列VBA技术资料增加681-690讲&#xff0c;T3学员看到通知后请免费领取,领取时间8月16日晚上19:00-8月17日中午12:00。本次增加内容&#xff1a; MF691:按所选范围对行进行分组显示 MF692:查找所给范围内的重复项 MF693:文本框Text…

python非交互连接mysql+mycat读写分离实现

python非交互连接mysql >>>import pymysql >>>connpymysql.connect(host"192.168.118.57",port3306,database"test",user"root",password"root") >>> cursorconn.cursor() >>> cursor.execut…

基于springboot的智能家居系统

TOC springboot198基于springboot的智能家居系统 研究背景与现状 时代的进步使人们的生活实现了部分自动化&#xff0c;由最初的全手动办公已转向手动自动相结合的方式。比如各种办公系统、智能电子电器的出现&#xff0c;都为人们生活的享受提供帮助。采用新型的自动化方式…

day22 Java基础——方法(干货)

day22 Java基础——方法 在Java中&#xff0c;方法是一段组织好的、可重复使用的代码块&#xff0c;用于执行一个特定的操作。方法提供了一种封装代码的方式&#xff0c;使得代码模块化&#xff0c;便于管理和重用。以下是关于Java中方法的一些基本介绍&#xff1a; 文章目录…

对话图像编辑研究综述

MGIE&#xff1a;MLLM 引导图像编辑&#xff08;ICLR 2024&#xff09; https://mllm-ie.github.io/ 利用 MLLM 来增强基于指令的图像编辑 (“what will this image be like if [instruction]” &#xff0c;来重写)。 训练好后&#xff0c;大视觉语言模型直接推导出简洁明确…

FreeRTOS队列(下)

文章目录 一、使用队列实现多设备输入1、增加旋转编码器2、使用队列集执行任务3、增加姿态控制&#xff08;使用MPU6050控制挡球板&#xff09; 二、队列实验_分发数据给多个任务(赛车游戏)三、传输大块数据四、示例&#xff1a;邮箱&#xff08;Mailbox&#xff09;五、队列集…

远程桌面你的凭据不工作解决方法

如果遇到“你的凭据不工作”的提示&#xff0c;请首先确认您输入的凭据是否正确。如果确认无误但仍然出现Windows远程桌面凭据不工作的提示&#xff0c;这可能是由于Windows安全设置的问题所导致的。要解决远程桌面连接提示你的凭据不工作这一问题&#xff0c;您可以尝试以下解…

qemu的VNC协议(RFB协议)

1、握手 1.1、服务器收到客户端TCP连接上后&#xff0c;服务器发送RFB的版本&#xff1a; 52 46 42 20 30 30 33 2e 30 30 38 0a RFB 003.008\n 1.2、客户端收到后回复&#xff1a; 52 46 42 20 30 30 33 2e 30 30 38 0a RFB 003.008\n 2、安全认证 2.1、服务器发送支…

MySQL数据库之part2

一、索引原理与慢查询优化 一&#xff09;介绍 1、为何需要有索引 一般的应用系统&#xff0c;读写比例是10:1左右&#xff0c;而且插入操作和一般的更新操作很少出现性能问题。在生产环境中&#xff0c;我们遇到最多的、也是最容易出问题的还是一些负责的查询操作。因此查询语…

密码学基础---椭圆曲线一文打尽

1.ECC简介及密钥生成 当前公认安全有效的三大类公钥密钥体制分别为基于大数因子分解难题(RSA)、离散对数难题(DSA)和椭圆曲线离散对数&#xff08;ECC&#xff09;难题的密码体制。 最初RSA由于其容易理解被广泛运用&#xff0c;但随着计算机性能的提升&#xff0c;要保证RS…