Unity基础框架从0到1(六)对象池模块

news2024/12/19 19:06:52

索引

这是Unity基础框架从0到1的第六篇文章,框架系列的项目地址是:https://github.com/tang-xiaolong/SimpleGameFramework

文章最后有目前框架系列的思维导图,前面的文章和对应的视频我一起列到这里:

文章

Unity基础框架从0到1 开篇

Unity游戏框架从0到1 (二) 单例模块

Unity基础框架从0到1(三)高效的全局消息系统

Unity基础框架从0到1(四)资源加载与管理模块

Unity基础框架从0到1(五)延时任务调度模块

视频

一 开篇

二 单例模块

三 消息模块

四 资源加载模块

五 延时任务调度模块

正文

下面这个图来源于游戏《吸血鬼幸存者》,在游戏中会存在满屏的怪物、子弹、伤害飘字等等,它们被创建,被销毁,爽感十足。

20230528-232553

但是CPU吐槽道:你倒是爽了,有没有考虑过我的感受???为啥它要吐槽呢?因为你每次创建一个对象时,它都需要到内存里去为它找到一块没人用且连续的区间,为它做初始化工作,最后把这个对象丢给你,然后你为这个对象设置一些信息并展示出来,你这个对象用完了其实也没有告诉它说你不用了,它可能要等到后面做清理时才会知道这个对象真的没用了,然后把这块连续的区间拿回去。

创建一个对象可以简单地分为这几个步骤:

1、找到并分配对象所需要的内存。

2、对象做原始的初始化工作。

3、对象本身设置信息。

这里主要是前两个步骤比较费(3也有可能费,但是这与业务有关,这里不讨论),找到内存其实在正常情况下是不费的,但是由于你疯狂地索要内存,还是不一样的东西,杂乱无章,即使你不用了,但是它还是不能简单把这个内存拿回去重新分配给其他地方(判断内存是否被使用代价大),这个期间你要分配新的内存,就不得不继续往后找,找到一个合适的地方。直接这么说可能大家不是很理解,接下来我来给大家举个🌰

示例

摆摊占位

比如去市场上摆摊,每个人摆摊所需要的空间大小不同,当你需要1米的摊位时,你走到街头一看,欸这两米被人占了,继续走,这里只有70厘米不够用,为啥后面的人要跨着占摊位导致这里有个小空间呢???噢原来他想把摊位摆到某个店旁边方便吃饭。

图一

继续往前走咯,终于找到了一个位置把东西放下,在这里贴一个条。

图二

有些人东西少,很快就卖完走了,但是他也没打招呼说自己不用这个摊位了,条还在上面贴着呢,有的人卖完一批回店里又去拿新的过来卖。所以后面再有人来找位置,也不敢就在这个贴了条但没人的地方摆,只能继续往后找。很快这条街就都被占满了,再有新的人过来摆摊,会发现没地方可以摆,只能找管理员问了,说前面有这么多没人的摊位,是不是可以清理一下给我摆呀?

图三

管理员就屁颠屁颠去帮忙查看,看那些摊位是不是真的没人了,他可能是打电话,可能是去找人确认,总之记住,这个步骤比较麻烦,所以管理员也不会轻易帮你这么做。经过一顿猛操作后,终于给腾出来一些空闲摊位了,把上面的条撕掉表示这里真没人了。

图四

面临的问题

从上面的步骤不难看出,由于大家摊位都不一样,并且需求也不同,所以很容易导致出现这种小的空间,加上大家摊位用完也不会说一声,所以你也没法简单直到某个空位是不是可以摆,只能往后找没贴条的空位。在内存中其实也是一样的,大家需要使用的内存大小不同,用完也不会告知这块内存用完了,分配时也会面临空隙太小不够用以及空白内存不敢用的情况。

你可能要说了,那大家用完把条撕了不就行了?那你这就对摆摊的人提出了较高的要求,并且肯定会有人忘记这么做,那这个摊位就会被一直占着了。在内存分配时,我们通常会由内存系统来为大家分配内存,并且在内部通过一些手段管理分配的内存,不需要大家用完告知(当然你也可以动态分配内存,这里不细讨论)。

解决方案——对象池技术

前面铺垫了这么长,抛出了两个问题,我们要怎么解决这个问题呢?摊主们自发组织了一个会议,决定大家直接申请一段较长的街道,并培养自己用完就撕条的习惯。由于1米的摊位使用量很大,并且卖的东西不多,很快就能卖完走人,而卖鱼的摊位设备布置麻烦,带走也麻烦,大家直接把一块长10米和长15米的连续空地都贴上条,约定了某个特殊标记表示摊位不用了,要用摊位时直接根据这个标记来识别。

图五

于是情况就变成这样了:一个参会过且摊位是1米的人过来了,他直接来到这10米摊位这里,被分配了一个摊位,另一个是摊位1米的人来了,发现这剩下的9米都被占了,因为不认识那个特殊标记,所以就往后走找其他摊位了。经过一段时间,某些参会过且摊位是1米的人用完了,把特殊标记还原回来走了,后面参会过且摊位是1米的人就知道,这个摊位虽然贴了条,但是实际没人用所以自己可以用。最后市场可能就是下图这样的,特殊标记不连续可能是有些人用完走了把标记抹了。

图六

通过这种方式,减少了呼叫管理员的次数(用完改标记,复用率高了),也不要求所有人都有用完撕条的意识,仅仅针对使用量大,且摊主更替比较频繁的摊位使用者。这其实就是对象池思路的一种应用,当然实际情况会比例子要稍微复杂一点,这里略去了一些细节,比如当有特殊标记的摊位满了怎么办?管理员真的只是沟通后把这些没人的摊位腾出来,会让其他人挪位置吗等等,感兴趣的可以自行探索下内存怎么分布的,系统怎么管理内存怎么做GC的。

对象池

概念

前面都是半讲故事的形式解释对象池技术,现在我们回归正题来给它一个标准定义,对象池技术是一种很常用的优化方法,它可以有效地减少内存的分配和回收。它适用于那些被频繁创建与销毁的物体、创建或销毁时开销很大的对象,文章开头图中的子弹与怪物无疑满足这个要求。

对象池技术的基本思想是,当需要创建一个新的对象时,先从一个预先创建好的对象集合中查找是否有可用的对象,如果有,就直接使用它,如果没有,就创建一个新的对象,并将它加入到对象集合中。当一个对象不再使用时,不是立即销毁它,而是将它标记为闲置状态,放回到对象集合中,等待下次使用。

对象池

优点

对象池技术有以下几个优点:

  • 减少了内存的分配和回收,避免了内存碎片化和垃圾回收带来的性能损耗。
  • 减少了对象的创建和销毁的开销,提高了游戏的运行效率。
  • 方便了对象的管理和复用,提高了代码的可读性和可维护性。

缺点

那对象池技术有什么缺点吗?再回到我们前面的示例,当我们有了这个制度后,需要购买更多的贴纸来作为特殊标记,同时,摊主需要掌握额外的知识,了解特殊标记的含义,最后,如果参会人忘记把特殊标记改回来,那这个摊位就永远被占用了,因为后续使用者不会去找管理员核对,只会无条件相信特殊标记。另外,前面提到了划分10米空地给1米的摊主,那如果每次都只有五个1米的摊主同时在卖东西,剩下的5米岂不是就白占浪费了吗?因此我们可以总结出对象池技术的缺点:

  • 需要额外的内存空间来存储对象集合,可能会占用较多的内存资源。
  • 需要维护对象集合的状态,可能会增加逻辑的复杂度和出错的风险。
  • 需要使用者严格遵循使用规则,只用不还会导致内存泄漏,还了还用会导致逻辑错误。
  • 需要根据不同的场景和需求来设计合适的对象池策略,可能会增加开发的难度和工作量,池子大小分配不合理可能导致内存浪费。

需要注意的点

设置初始数量

为对象池设置初始数量,并在某个时机提前创建好一定数量的对象便于某些系统可以直接拿去用,这样可以避开内存分配高峰从而减少卡顿。比如在进入战斗前读条时,我们事先创建好五十个子弹,实际战斗时则可获得子弹去显示,无需在复杂战斗场景中还进行开销比较大的创建行为。

设置最大数量

设置合适的最大数量一方面可以避免占用过多内存却不使用(一般会先创建一个能容纳最大数量对象的池),另一方面也避免了部分系统无限制索要内存使得卡顿。在达到最大数量后,继续从池中获取对象时,如果没有可用的对象,通常需要采取一定措施,比如:

  • 比较重要的对象池可以设置一个很大的最大数量;
  • 一些对象创建出来不太显眼,可以选择不创建;
  • 一些对象创建后可以掩盖现有的对象,可以对现有的对象做清理,提前进入回收环节。

由于设置最大数量具备主观性,我们还可以考虑增加一些机制来对对象池做检查,如果某些对象池池中有很多对象,但实际游戏中往往只有几个对象会被使用,则可以动态调整对象池大小,减少其占用的内存。

做好清理工作

同一个池中的对象可能用在不同地方,在其他地方使用时可能会残留一些数据,干扰到新使用的地方,因此需要做好清理工作。比如我们建立了一个Vector3的列表池,在某个系统中我们从池中拿到了一个列表,并把寻路的结果存进去。如果这个时候忘记做清理工作,可能在列表中已经存在几个Vector3的数据了,从而导致寻路出问题。

避免用完不还,还完还(hai)用

如果某个对象从池中取出后不用了,但是没有归还,会导致对象池一直以为这个对象被使用,从而无法再回收这个对象让其他人用。如果一个对象还了又继续使用,可能导致其他地方的数据出问题,别人已经在用这个对象了,你又继续修改对象内容。

实现

本文旨在实现一个通用的对象池和一个Unity的对象池,前者用于创建通用的对象,后者用于创建Unity的对象。文章中的代码均已上传到Github,感兴趣的可以看看,觉得有用也不妨给个Star~ [https://github.com/tang-xiaolong/SimpleGameFramework]

由于对象池可能会存在很多个,我们不可能在每个使用的地方都事先去创建一个对象池,然后再从对应池中取需要的对象,因此本文提供了对象池的工厂类,当需要获取一个对象时,不直接与对象池交互,而是直接与工厂交互,由工厂来维护对象池,对象池本身来维护对象。

在游戏开发过程中,经常会有一些需要自动回收的资源,比如某个粒子播放时长是3s,那它可能就是需要在3秒后回收,因此本文提供了一个自动回收的设置,让某些对象可以在创建后被对象池自动回收,自动回收任务是使用了前一节中的延时任务调度模块实现的,在本节中使用的延时任务调度模块已做了改进,为任务增加了唯一Id使得任务不会被错误使用,改进目的与方案后续会出文章来阐述,本文不赘述。

在处理Unity Object对象时,无可避免需要加载游戏资源,本文提供一个简单的资源加载类,实际放入项目中应该是接入项目的资源加载类。

对象池模块的主要脚本及功能

下面列举对象池模块的主要脚本以及功能,具体使用请下载项目查看,这里不做说明了,后续也会有专门的视频来解读。

资源加载

TestAssetLoad负责加载资源,内部实现了一个资源加载的方法。

自动回收

AutoRecycleConfigItem配置了每个回收的对象名字和回收时间。

AutoRecycleConfig负责在解析时临时保存AutoRecycleConfigItem配置。

AutoRecycleConf负责维护自动回收的配置,内部配置使用字典形式保存。

AutoRecycleItem是运行时自动回收对象实例,当存在一个自动回收对象时,会创建一个自动回收的任务,任务的uid保存在这个类中。

对象池

IObjectPool定义了对象池的几种行为,包括获取对象,回收对象,清理对象,进池离池处理。

ObjectPool是一个通用的对象池,其实现了IObjectPool定义的行为。

ObjectPoolFactory是通用对象池的工厂类,负责对外提供不同的对象,外界通过工厂类直接取得产品,由工厂类来创建生产产品的对象池并维护行为。

UnityObjectPool是一个Unity Object对象池,实现了IObjectPool定义的行为。

UnityObjectPoolFactory是Unity Object对象池的工厂类,负责对外提供Unity Object的产品。在此类中还维护了自动回收配置的读取,自动回收任务的创建与销毁。实际资源的加载通过外界设置的资源加载方法加载。

思维导图

图片估计看不清楚,可以下载下来查看:https://img-bucket11.oss-cn-hangzhou.aliyuncs.com/BlogImage/20230602013119.png

Unity游戏框架从0到-1

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

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

相关文章

算力不竭如江海,天翼云“息壤”如何助力千行百业算力智能调度?

科技云报道原创。 数字时代下,算力已成为新型生产力,并朝着多元泛在、安全可靠、绿色低碳的方向演进。以算力为核心的数字信息基础设施,是国家战略性布局的关键组成部分,也成为数字经济时代的“大国重器”。 作为云服务国家队&am…

报表生成器FastReport .Net教程:“Text“对象、文本编辑

FastReport .Net是一款全功能的Windows Forms、ASP.NET和MVC报表分析解决方案,使用FastReport .NET可以创建独立于应用程序的.NET报表,同时FastReport .Net支持中文、英语等14种语言,可以让你的产品保证真正的国际性。 FastReport.NET官方版…

es elasticsearch 十四 各种机制 评分机制 正序索引 解决跳跃结果问题 解决耗时过长问题 解决相同属性值都到一个地方

目录 评分机制 机制 查看评分实现如何算出来的explaintrue 分析能否被搜索到 Doc value 正排序索引 Query phase Fetch phase Preference 问题 解决跳跃结果问题 Timeout 到达时间直接返回,解决耗时过长问题 Routing 数据准确分配到某地,解决相…

这才叫软件测试工程师,你那最多是混口饭吃罢了....

前些天和大学室友小聚了一下,喝酒喝大发了,谈天谈地谈人生理想,也谈到了我们各自的发展,感触颇多。曾经找工作我迷茫过、徘徊不,毕业那会我屡屡面试失败,处处碰壁;工作两年后我一度想要升职加薪…

006+limou+C语言“堆的实现”与“树的相关概念”

0.前言 这里是limou3434的一篇个人博文,感兴趣可以看看我的其他内容。本次我给您带来的是树的相关只是,并且把堆这一数据结构做了实现,后面还有大量的oj题目。但是树重点也就在这十多道oj题目中,您可以尝试着自己做一下&#xff…

我的创作纪念日|写在CSDN创作第512天

机缘 今天无意中发现CSDN后台给我发送私信,才发觉原来我的第一篇博客更新已经过去512天了,512天一晃而过居然还有点恍然。 作为一名网络专业的在校大学生,最初开始查找相关的资料其实更习惯于从外站进行查找,却总是在不经意中进入…

人事管理项目-前端实现

人事管理项目-前端实现 引入Element和Axios开发Login页面配置路由配置请求转发启动前端项目 引入Element和Axios 前端UI使用Element,网络请求则使用Axios,因此首先安装Element和Axios依赖,代码如下: 依赖添加成功后,接…

N-propargyloxycarbonyl-L-lysine,1215204-46-8,是一种基于赖氨酸的非天然氨基酸 (UAA)

产品描述: N-ε-propargyloxycarbonyl-L-lysine (H-L-Lys(Poc)-OH) 是一种基于赖氨酸的非天然氨基酸 (UAA)。 广泛用于多种生物体中荧光探针的生物偶联。 N- ε- Propargyloxycarbonyl-L-lysine (H-L-Lys (Poc) - OH) is a non natural amino acid (UAA) based on …

Kotlin Channel系列(一)之读懂Channel每一行源码

文章目录 有话说概述初识ChannelChannel种类Channel五大金刚SendReceiveClosedQueueBuffer Channel的行为Channel源码分析发送数据大动脉接收数据大动脉父类默认实现方式(RendezvousChannel)发送流程send()函数onSend()函数 接收流程receiveCatching()函数onReceiveCatching()函…

基于图像处理的圆检测与深度学习

基于图像处理的圆检测与深度学习 摘 要一、 绪论二 、图像预处理2.1 滤波算法2.2 边缘检测 三 、圆识别与定位算法3.2 定位算法3.2.1 迭代算法 4.1 数据处理 五、深度学习介绍:参考文献 摘 要 本文主要论述在图像处理的的基础上,为了克服图像背景中的亮…

SpringBootWeb案例-2(下)

3. 修改员工 需求:修改员工信息 在进行修改员工信息的时候,我们首先先要根据员工的ID查询员工的信息用于页面回显展示,然后用户修改员工数据之后,点击保存按钮,就可以将修改的数据提交到服务端,保存到数据…

面试专题:java虚拟机(2)

8.垃圾收集有哪些算法,各自的特点? 标记清除 直接将要回收的对象标记,发送gc的时候直接回收:特点回收特别快,但是回收以后会造成 很多不连续的内存空间,因此适合在老年代进行回收,CMS(current…

Linux--ServerProgramming--(4)详解 I/O复用

1. I/O 复用功能 I/O 复用能同时监听多个文件描述符。 I/O 复用本身是阻塞的。 当有多个文件描述符同时就绪时:若不采取额外措施,程序就只能按顺序一次处理其中的每一个文件描述符,这使得服务器程序看起来是串行工作的。若要实现并发&#…

ChatGPT市场营销指南震撼出炉,你错过了?!

ChatGPT是一种基于AI技术的语言模型,它可以与用户进行对话和交互。它被广泛应用于各个领域,包括市场营销。作为一名市场营销人员,您可以使用ChatGPT来获得创意、解决问题和生成内容。 下面是190个ChatGPT提示,可帮助营销人员更好…

oracle自定义函数 for in loop示例

1、新建type,就是返回结果集有什么,这里就写什么(相当于表的字段) CREATE OR REPLACE TYPE "TYPE_NQ_FORM_STATISTICS" as object (recordid varchar2(500),form_name varchar2(200),sortone varchar2(100),sorttwo …

华为od机试题目回顾

今天去做了华为机试&#xff0c;两道一星题&#xff0c;一道二星题。 一星题 1&#xff1a; 题目主要大意&#xff1a; 输入一串字符串&#xff0c;里面可能包含有(x,y)的坐标。 0<x<1000&#xff0c;0<y<1000&#xff0c;类似(01,1)、(1,01)、(0,100)的都是非法坐…

Java开发手册中为什么不建议在for循环中使用“+“进行字符串操作

场景 java开发手册中对于循环体中进行字符串的拼接要求如下&#xff1a; 【推荐】循环体内&#xff0c;字符串的连接方式&#xff0c;使用 StringBuilder 的 append 方法进行扩展。 说明&#xff1a;下例中&#xff0c;反编译出的字节码文件显示每次循环都会 new 出一个 Str…

【Linux】-自动化构建工具(make/makefile)

作者&#xff1a;小树苗渴望变成参天大树 作者宣言&#xff1a;认真写好每一篇博客 作者gitee:gitee 如 果 你 喜 欢 作 者 的 文 章 &#xff0c;就 给 作 者 点 点 关 注 吧&#xff01; 文章目录 前言 前言 今天我们来讲讲再Linux中开发必备的一项技能&#xff0c;没有这个…

【OpenMMLab AI实战营第二期】深度学习预训练与MMPretrain

深度学习预训练与MMPretrain MMPreTrain 算法库介绍 MMPretrain 是一个全新升级的预训练开源算法框架&#xff0c;旨在提供各种强大的预训练主干网络&#xff0c; 并支持了不同的预训练策略。MMPretrain 源自著名的开源项目 MMClassification 和 MMSelfSup&#xff0c;并开发…

项目干系人管理实用方法,让你的项目顺风顺水

项目管理中的干系人是每个项目的一个重要方面&#xff0c;因为项目的结果取决于他们。然而&#xff0c;管理各种各样的干系人的艺术很有挑战性。在项目管理中根本没有出错的余地&#xff0c;本文将带你了解项目干系人以及如何管理他们以促进项目的全面成功。 谁是项目管理的干…