对象池的学习与在Unity中使用的“坑”

222000305陈宇焜 学生 2023-06-06 13:01:09

目录

  • 一、技术概述
  • 二、技术详述
  • 定义与实现
  • 更好的对象池
  • 三、学习问题总结
  • 四、总结
  • 五、参考资料

一、技术概述

对象池常使用于大量游戏对象的维护上。作为游戏优化的大头,其实现可以很简单也可以很复杂,这里举例说明多类型对象池的学习记录。此处对象池异于引用池。在Unity中使用常用的对象池时,需要理解对象池的的原理和Unity的生命周期,而此处的“坑”也和一种对象池的实现有关(详见学习问题总结)。

二、技术详述

定义与实现

首先,为了实现一个比较完整的对象池,应当让每一种类型的对象都有对应的池子,因此可以引申出一个简单的模型:

public class ObjectPoolManager{
    public Dictionary<Type,List<GameObject>> MultiTypeObjectPool;
}

这里定义了一个提供多类型的对象池,可以提供不同对象的复用工作,当然这里可以把List再封装为一个ObjectPool进行更加深入的管理。

基础的对象池需要对象的创建、回收功能。初次创建直接使用Gameobject.Instantiate(),而回收则是SetActive(false),再次使用时,反过来设为true。

public class ObjectPoolManager{
    public Dictionary<Type,List<GameObject>> MultiTypeObjectPool;
    public GameObject Spawn<T>(){}
    public GameObject Despawn(GameObject){}
}

更好的对象池

当然,为了让对象池能够发挥更大的作用,应该对生成方法有多个不同的方法,例如重载一个生成方法使得通用性提高,不过内部实现常常会一个方法复用一个基础方法,让栈中堆积。还可以按需求提供生成的对象,例如是否复用是否需要创建对象池
另外,为了避免内存泄漏,应该防止用户滥用的情况发生,对已缓存的对象进行检查并释放,还可以提供其他时间限定选项。

三、学习问题总结

  • 初始化问题
    • 对象池复用对象时,已经不会重新调用Awake和Start了,所以应当在OnEnable中进行重新初始化,保证每次显示的游戏对象都是“新的”。特别是对其他对象的引用,一旦发生变化,需要及时调整。
  • 监听事件与释放
    • 在需要复用的对象上,可能会注册对某个事件的监听,然而对象回收后一般不会去检测某个委托的从属对象是否激活,于是当事件抛出后依然会调用不需要的处理方法,但是我们可能会在对象将被释放时才注销监听,然而复用并不会释放。
  • 复用对象的管理
    • 对象池所复用的对象应该得到良好的管理,例如遵循Instantiate()的参数支持设置父级,或者统一管理在对象池本身的GameObject下,或者两者皆有。
      在团队项目使用的对象池就不支持两者任一,使用起来很不方便。

四、总结

对象池提供了很好的优化机制,但也存在滥用的情况,并且具有良好功能的对象池虽然有标准的实现,但也存在一定学习难度,特别是配合其他系统的时候,对整体框架思想需要有良好的把握。明白对象复用的原理,避免在各个环境下出现Bug。

五、参考资料

ObjectPool-Gameframework,

...全文
177 回复 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

686

社区成员

发帖
与我相关
我的任务
社区描述
2023年福州大学软件工程实践课程W班的教学社区
软件工程团队开发软件构建 高校 福建省·福州市
社区管理员
  • FZU_SE_teacherW
  • aboutazhang
  • 郭渊伟
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧