Unity Class深拷贝问题分析

Unity Class深拷贝问题分析

  • 前言
  • 常用解决方案
    • 1.手动复制字段
    • 2.使用序列化工具
    • 3.使用Instantiate方法(只能用于MonoBehaviour)
    • 4.重写运算符赋值
    • 5.使用Visual Scripting中提供的拷贝函数(推荐)

深拷贝

前言

在Unity项目中,我们面临一个读取数据表并深拷贝该类的问题。具体情况是这样的:我们需要从数据表中读取人物的数据,但在战斗过程中,人物的数据会不断发生变化。因此,我们需要一个数据类来存储人物的数据,并且希望在不修改原始数据表的情况下,创建一个副本用于战斗。

为了实现这一逻辑,我们采取了以下步骤:首先,我们将Json或Xml格式的数据表反序列化为原始数据类,使用工具进行反序列化操作。然后,我们对原始数据类进行深拷贝,创建一个战斗数据类的副本。通过这种方式,我们既可以使用原始数据表中的数据,又能在战斗过程中对战斗数据类进行修改,而不会影响原始数据表的功能。

这样做的好处是,我们可以在战斗中独立使用战斗数据类,而不会影响原始数据表的完整性。同时,通过深拷贝的方式,我们确保战斗数据类是一个全新的对象,可以独立于原始数据类进行修改,避免了对象引用带来的问题。

常用解决方案

1.手动复制字段

如果类的字段较少且结构简单,可以手动复制每个字段来创建新的对象。这需要逐个复制类的每个字段,并确保复制的是字段的值而不是引用。

public class MyClass
{
    public int myInt;
    public string myString;

    public MyClass DeepCopy()
    {
        MyClass newObject = new MyClass();
        newObject.myInt = myInt;
        newObject.myString = myString;
        return newObject;
    }
}

2.使用序列化工具

使用JsonUtility、MsgPack、Protobuf 等工具库进行序列化和反序列化功能,并能够处理更复杂的类结构。通过将对象序列化为字节流,然后再反序列化为新的对象,可以实现深拷贝。
比如下面这种:

TIP:别用这个,这是我当前项目的,没有对应类用不了

    /// <summary>
    /// Json文件转实体类
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="value"></param>
    /// <returns></returns>
    public static List<T> JsonToObject<T>(string value) where T : ConfigJsonBase
    {
        List<T> lst = new List<T>();
        var test = JsonConvert.DeserializeObject<ConfigJsonContainer>(value, settings);
        test.CopyListToDic();
        foreach (var item in test.dataMap)
        {
            T line1 = (T)item.Value;
            lst.Add(line1);
        }
        return lst;
    }

相当于再次从表中序列化一次获得一个全新的拷贝

3.使用Instantiate方法(只能用于MonoBehaviour)

使用 UnityEngine.Object.Instantiate方法:如果需要复制 Unity 引擎的 GameObjectMonoBehaviour,可以使用 Instantiate方法来创建它们的副本。这个方法会创建一个全新的实例,包括所有的组件和属性,并将它们与原始对象解耦。

public class CopyExample : MonoBehaviour
{
    public GameObject originalObject;
    private GameObject copiedObject;

    public void PerformCopy()
    {
        copiedObject = Instantiate(originalObject);
        // 对复制对象进行进一步操作...
    }
}

4.重写运算符赋值

下面这个案例是通过重写&运算符实现创建一个新的类并将所有字段赋值。
通过使用&运算符创建新对象时,可以通过将原始对象作为第一个参数传递给运算符,并忽略第二个参数,以触发运算符的重载。新的 newCard对象将具有与原始对象相同的字段值。

这种方法依赖于运算符的重写,并且在使用时需要注意运算符的语义和正确使用方式。另外,由于 & 运算符通常与按位与操作相关,重写它来创建新对象可能会使代码的可读性降低。因此,在实际使用时,建议谨慎选择是否使用这种重写运算符的方法,以确保代码的清晰性和可维护性。

public class CfgCardProperties : ConfigJsonBase
{
    public string _CardName;
    public List<string> _CardIconPath;
    public bool _IsShowCardUnder;

    public static CfgCardProperties operator &(CfgCardProperties card, CfgCardProperties cfg)
    {
        CfgCardProperties newCard = new CfgCardProperties();
        card.ID = cfg.ID;
        card._CardName = cfg._CardName;
        card._CardIconPath = cfg._CardIconPath != null ? new List<string>(cfg._CardIconPath) : null;
        return newCard;
    }
}

用法是

var cfg = new CfgCardProperties();
cfg &= originalCfgs[i];

5.使用Visual Scripting中提供的拷贝函数(推荐)

Unity Visual Scripting中,CloneViaFakeSerialization节点可以用于实现对象的深拷贝。该节点在 Bolt 或其他 Unity 可视化脚本工具中提供,它通过序列化和反序列化对象来创建其副本。

CloneViaFakeSerialization节点的工作原理如下:

  1. 将要克隆的对象进行序列化,将其转换为字节流。
  2. 将字节流反序列化为一个新的对象。

在上面例子中只需要一行就可以实现类的深拷贝

using Unity.VisualScripting;

cfg= originalCfgs[i].CloneViaFakeSerialization();

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

web前端-TypeScript学习

web前端-TypeScript学习 TypeScript 介绍TypeScript 初体验安装编译TS的工具包编译并运行TS代码 TypeScript 常用类型类型注解常用基础类型原始类型数组类型类型别名函数类型对象类型接口元祖类型推论类型断言字面量类型枚举any类型typedof TypeScript 高级类型class类class的基…

笔记:WebRTC 网络技术理论与实战(二)

WebRTC技术笔记 笔记&#xff1a;WebRTC 网络技术理论与实战&#xff08;一&#xff09; 作者&#xff1a;李俊才 &#xff08;jcLee95&#xff09;&#xff1a;https://blog.csdn.net/qq_28550263 邮箱 &#xff1a;291148484163.com 本文地址&#xff1a;https://blog.csdn.n…

C语言之文件的读写(1)

前面三部分已经给大家介绍过了&#xff0c;网址发给大家方便大家复习 打开方式如下&#xff1a; 文件使用方式 含义 如果指定文件不存在 “r”&#xff08;只读&#xff09; 为了输入数据&#xff0c;打开一个已经存在的文本文件 出错 “w”&#xff08;只写&#xff09; 为了输…

OC(iOS)中常见的面试题汇整(大全)

你如何理解OC这门语言的?谈一下你对OC的理解? ​​​​​​​ OC语言是C语言的一个超集,只是在C语言的基础上加上了面向对象的语言特征,如:继承,封装,多态. 封装:把属性和方法封装成一个类,方便我们使用 多态:不同对象对于同一消息的不同响应,子类可以重…

同时安装vue-cli2和vue-cli3

同时安装vue-cli2和vue-cli3 发布时间环境安装后的效果安装vue-cli2安装vue-cli3vue-cli3和vue-cli2的区别vue-cli2目录结构vue-cli3目录结构 发布时间 vue版本发布时间Seed.js2013年vue最早版本最初命名为Seedvue-js 0.62013年12月更名为vuevue-js 0.82014年1月对外发布vue-j…

微软ChatGPT技术的底层支撑——GPU

我是荔园微风&#xff0c;作为一名在IT界整整25年的老兵&#xff0c;今天我们来看一看微软ChatGPT技术的底层支撑——GPU。 想要了解GPU&#xff0c;你必须要清楚CPU、GPU、TPU三者的关系。 微软的chatgpt是基于复杂的人工神经网络和强化学习的技术&#xff0c;这是如何运算的…

io.netty学习(八)零拷贝原理

目录 零拷贝 传统I/O操作存在的性能问题 零拷贝技术原理 虚拟内存 mmap/write 方式 sendfile 方式 带有 scatter/gather 的 sendfile方式 splice 方式 总结 io.netty学习使用汇总 零拷贝 零拷贝&#xff08;Zero-Copy&#xff09;是一种 I/O 操作优化技术&#xff0c…

web漏洞-反序列化之PHPJAVA全解(上)(37)

这个很重要 为什么会产生这个东西&#xff1a;序列化之后便于我们对象的传输和保存&#xff0c;这个作用就是为了数据的传递和格式的转换&#xff0c;我们称之为序列化。 在这给过程中&#xff0c;会涉及到一种叫做有类和无类的情况&#xff0c;开发里面经常看到的一个东西&a…

AbstractQueuedSynchronizer源码

介绍 基于队列的抽象同步器&#xff0c;它是jdk中所有显示的线程同步工具的基础&#xff0c;像ReentrantLock/DelayQueue/CountdownLatch等等&#xff0c;都是借助AQS实现的。 public abstract class AbstractQueuedSynchronizerextends AbstractOwnableSynchronizerimplemen…

使用omp并行技术加速最短路径算法-迪杰斯特拉(Dijkstra)算法(记录最短路径和距离)

原理&#xff1a; Dijkstra算法是解决**单源最短路径**问题的**贪心算法** 它先求出长度最短的一条路径&#xff0c;再参照该最短路径求出长度次短的一条路径 直到求出从源点到其他各个顶点的最短路径。 首先假定源点为u&#xff0c;顶点集合V被划分为两部分&#xff1a;集合…

【玩转Linux操作】Linux服务管理

&#x1f38a;专栏【玩转Linux操作】 &#x1f354;喜欢的诗句&#xff1a;更喜岷山千里雪 三军过后尽开颜。 &#x1f386;音乐分享【如愿】 大一同学小吉&#xff0c;欢迎并且感谢大家指出我的问题&#x1f970; 文章目录 &#x1f354;服务(service)管理⭐service管理指令 &…

chatgpt赋能python:Python如何快速提取指定行和列的数据?

Python如何快速提取指定行和列的数据&#xff1f; 在进行数据分析和处理时&#xff0c;常常需要从海量数据中筛选出所需的数据。这时&#xff0c;Python是一款非常强大的工具&#xff0c;可以方便地进行大规模数据清洗和筛选。本文将介绍如何使用Python快速提取指定行和列的数…

chatgpt赋能python:Python提取指定位置字符

Python 提取指定位置字符 Python 是一种高级程序语言&#xff0c;其易读性、简单易学性和易维护性使其成为最受欢迎的编程语言之一。它可以用于各种数据分析和科学计算&#xff0c;包括搜索引擎优化&#xff08;SEO&#xff09;。 在SEO中&#xff0c;提取和处理数据是一个重…

监听关闭浏览器触发事件

关闭和刷新页面都会触发&#xff0c;一般都不用来做弹窗提示&#xff0c;一般用来做数据操作 // 监听页面关闭 清除本地缓存 window.onbeforeunload function (e) { localStorage.removeItem("statement"); }; // 监听页面关闭 提醒是否关闭 现在不允许自定义内容了…

【深度学习】5-1 与学习相关的技巧 - 参数的更新(Momentum,AdaGrad, Adam )

神经网络的学习的目的是找到使损失函数的值尽可能小的参数。这是寻找最优参数的问题&#xff0c;解决这个问题的过程称为最优化。 但是神经网络的最优化问题非常难。这是因为参数空间非常复杂&#xff0c;无法轻易找到最优解。而且&#xff0c;在深度神经网络中&#xff0c;参…

selenium.chrome怎么写扩展拦截或转发请求?

Selenium WebDriver 是一组开源 API&#xff0c;用于自动测试 Web 应用程序&#xff0c;利用它可以通过代码来控制chrome浏览器&#xff01; 有时候我们需要mock接口的返回&#xff0c;或者拦截和转发请求&#xff0c;今天就来实现这个功能。 代码已开源&#xff1a; https:/…

9k字长文理解Transformer: Attention Is All You Need

作者&#xff1a;猛码Memmat 目录 Abstract1 Introduction2 Background3 Model Architecture3.1 Encoder and Decoder Stacks3.2 Attention3.2.1 Scaled Dot-Product Attention3.2.2 Multi-Head Attention3.2.3 Applications of Attention in our Model 3.3 Position-wise Feed…

C++基础(6)——类和对象(运算符重载)

前言 本文主要介绍了C中运算符重载的基本知识。 4.5.1&#xff1a;加号运算符重载&#xff08;成员函数和全局函数都可实现&#xff09; 运算符重载&#xff1a;对已有的运算符重新进行定义&#xff0c;赋予其另一种功能&#xff0c;以适应不同的数据类型 1&#xff1a;成员…

防火墙日志记录和监控在网络安全中的重要性

防火墙监视进出网络的流量&#xff0c;并保护部署网络的网络免受恶意流量的侵害。它是一个网络安全系统&#xff0c;根据一些预定义的规则监控传入和传出的流量。它以日志的形式记录有关如何管理流量的信息。日志数据包含流量的源和目标 IP 地址、端口号、协议等。为了有效地保…

Git系列:运用Git创建空白分支进行项目相关文档管理

文章目录 起因一、为什么会选择Git分支二、Git分支的简单介绍和好处三、本次的具体操作1.$git checkout --orphan XXX2.删除当前分支里的内容3.提交新的分支 总结 起因 项目管理过程中没有做好相关文档管理&#xff0c;比如需求&#xff0c;开发&#xff0c;测试等文档&#x…