当前位置: 首页 > news >正文

UE开发中的设计模式(三) —— 对象池模式

在FPS游戏中,射击会生成子弹,在命中敌人后子弹会被销毁,那么会导致子弹对象频繁地创建和销毁,会造成运行效率降低且会产生内存碎片问题,而对象池模式可以很好地解决这个问题。

文章目录

  • 问题提出
  • 概述
  • 问题解决
  • 总结


问题提出

正如引言所说,FPS游戏中射击会频繁地创建和销毁子弹,导致效率降低且产生大量的内存碎片。

同时,按照设计模式的原则,我们需要遵守开放封闭原则,我们希望对象池除了应用在子弹创建和销毁中,还可以应用在其他场景下,即复用我们的对象池抽象类与对象池中对象的抽象类,且对于新增场景,只需要增加相应的对象池实现类与对象池中对象的实现类,而不需要修改抽象类中的代码。


概述

根据上文我们提到的需要,对象池模式的UML类图设计如下。

  • Abstract Object Pool 抽象的对象池类,其保存了对象池的大小,以及所有的抽象的目标对象。用户可以通过 GetObject 从对象池中获取一个可用的对象。
  • Concrete Object Pool 具体的对象池类,根据要保存的对象类型,创建特定的对象数组,并进行相应的初始化。
  • Abstract Pool Actor 抽象的目标类,inUse 标记其是否被使用,我们从对象池中取出一个目标使用,需要通过 SetInUse(true) 来进行相应的设置,比如对于子弹我们要让其可见、开启碰撞、设置初速度等,当目标被还给对象池(可能是主动还,可能是超时还),需要通过 SetInUse(false) 来还原为初始设置,比如让子弹不可见、关闭碰撞、设置0速度等。
  • Concrete Pool Actor 具体的目标类,需要重写 SetInUse、构造函数和析构函数,因为不同的目标类,他需要初始化的东西不同,析构释放的资源也可能不同。

问题解决

下面我们应用对象池解决上面子弹的问题

(1) 创建一个 BP_PooledActor 的目标抽象类其有属性 inUseTimeToLiveTimeToLiveTimer 后两个属性用于超时返还到对象池中。

自定义事件 CS_SetInUse 如果传入真,关闭碰撞、关闭Tick、隐藏于游戏,设置一个定时器来超时返还。

(2)创建一个 AC_ObjectPool 组件,其有属性 PoolSizeTimeToLiveObjectPoolPooledActorClassObjectPool 是一个数组保存目标,PooledActorClass 保存目标类的类型。

自定义事件 CS_InitializePool 用来初始化对象池,根据 PoolSize 创建目标对象加入对象池

定义函数 F_FindFirstAvailable 用于找到可用的目标对象

定义函数 F_SpawnFromPool 用于用户从对象池中获取目标对象

(3)创建 FirstPersonProjectile 子弹类,其父类为 BP_PooledActor
重写 CS_SetInUse,加入设置投射组件速度和激活/关闭粒子系统

在 Hit 事件中,CS_SetInUse(false) 返还给对象池。

(4)在角色类中,加入 AC_ObjectPool 组件,那么就可以在开火的时候使用子弹对象池中的子弹了


总结

优点:

  • 减少频繁创建和销毁对象的开销,提高系统性能。
  • 控制资源的最大使用量。

缺点:

  • 需要正确管理对象的状态重置,避免状态泄露。
  • 增加了复杂性,需要谨慎管理对象生命周期。
  • 需要我们评估一个合理的资源的最大使用量,过大会导致额外的内存开销,过小可能会导致错误(需要更复杂的处理手段)

适用场景:
对象池适用于我们需要频繁创建和销毁一个对象,且创建销毁开销较大的场景,以帮助我们减少创建销毁的次数,提升性能,同时减少内存碎片。

上面提到的对象池用法比较初级,更深入地对象池使用还有根据对象池使用情况,动态地增减对象池中的对象。

http://www.lryc.cn/news/424845.html

相关文章:

  • Mocha测试框架:JavaScript自动化测试的瑞士军刀
  • flask实现Streaming内容传输
  • seata的使用(SpringBoot项目整合seata)
  • docker容器和宿主机网络不通
  • 编程学习之旅:高效记录与整理笔记的艺术
  • dev c++中,在C++11模式下编译带M_PI宏的文件报错的解决办法
  • 【ubutnu24.04】k8s部署2:摸索修复问题
  • 处理JSON数据时遇到的解析错误:“Unexpected character (`“`)”
  • RDKit|分子输入输出格式解析(如 SMILES、Mol、SDF)
  • 【模电笔记】——反馈放大电路
  • 【面试题】Redis缓存问题全解:击穿、雪崩与穿透
  • 676. 实现一个魔法字典
  • Spring Boot 入门以及对微服务的理解
  • 仿RabbiteMq实现简易消息队列正式篇(需求分析)
  • Python酷库之旅-第三方库Pandas(082)
  • 0101中文乱码-BufferedImage-图片处理
  • [Qt][Qt 事件][下]详细讲解
  • 八股总结----计算机网络
  • Laravel 框架开发 ERP 系统,技术选型和分析以及实施计划
  • 【Vue3】嵌套路由
  • pygame小游戏
  • .Net Core IIS 程序报错 Access to the path c:\\windows\\TEMP\\poifiles is denied
  • 交换机VLAN配置中Tagged与Untagged端口的差异和应用区别
  • @OneToOne注解的作用
  • vue动画、过渡效果
  • 在 Vue 3 项目中使用 Element UI Plus <el-calendar>组件与时区处理
  • 【系统架构设计】计算机网络
  • 《中国数据库前世今生》——历史的深度与未来的展望
  • web前端之实现霓虹灯背景魔术卡、旋转的背景动画、模糊效果、边框、变量、filter
  • 几款免费的时序数据库对比