Unity 简易对象池

“每隔x秒随机产生10-20个物体(cube或者sphere),要求显示在屏幕上,并在x秒的显示后将其回收”。看似简单的题目小菜也楞是在紧张中满头大汗的调试了两个小时左右才得以完成

    本篇就来讨论下对象池的那些事。对象池的概念也算是老生常谈的话题了,小菜简单直白的理解就是解决瞬间克隆(Instance)大量对象带来的性能问题,将预创建和已使用过的对象缓存起来供下次的直接使用,用内存来换取性能的一种手段。

    面试中面试官常常提及到你的性能优化手段和你解决过游戏卡顿的实操方法。对象池就是其中一种,那个被举的最多的例子就数:Player发射大量子弹的过程吧。实际情况也确实是这样,更多的情况还有游戏特效,UI上的滑动列表甚至是音效播放等等。预加载和对象池在游戏研发中尤为重要。

    回忆往昔,小菜兴趣燃起又将自己编写的对象池拿出来分享下

    先上小菜的uml类图吧(家里没网没有工具将就下吧)

    

    尽管网上给出了茫茫多的对象池设计模型,而在这里仅仅代表小菜自己的见解和使用,望各位大佬莫要吐槽

 

对象池解析

    首先从上图中可以直观看出,小菜包装了4个类。这4个类的作用分别是:

    1).ResPool            

        小菜以一类GameOjbect划分为一类对象池。而每一类对象池又以一个字符串的key作为索引。ResPool 便是对象池个体的包装。

    2).ResPoolMgr

        故名思意这是一个管理众多(ResPool)对象池个体的类。ResPool与ResPoolMgr属于聚合关系。ResPoolMgr包含ResPool对象,但ResPool并不是ResPoolMgr的一部分。

    3).AssetMgr

        通常AssetMgr这一层打交道的一般是所有资源的加载管理,包括AssetBundle、Resource、AssetDataBase各种同步异步等。小菜的演示过程里简化了,AssetMgr仍代表资源加载的核心接口类。

    4).PoolKeyDefine

     PoolKeyDefine仅仅作为一个ResPool的key的定义类,抽离出来的目的是由于项目中要做大量的频繁修改。根据对象的开闭包装原则,我们最不希望的是修改编码的时候来轻易侵入触动我们设计的核心类里。

 

对象池编码

1).ResPool      

 

大量的接口说明都已经在注释中详细说明。mObjList便是维护存入池子的集合。mOriginalRes为存入的原始对象,要小心处理避免将原始对象也给回收了

 

2).ResPoolMgr

 

本类并不需产生多余的实例,小菜定义为了单例类。仅仅通过对象的静态实例来访问。

 

3).AssetMgr

 

 

 4).PoolKeyDefine

    最后是这个定义key的类,仅仅是为了约束开发时的规范不至于开发时常常写错

 

外部调用接口

1).弹出obj对象

GameObject tempObj = AssetMgr.GetInstance().PopGameObject(PoolKeyDefine.CreateCube, obj);

 

2).回收obj对象

 AssetMgr.GetInstance().PushGameObject(PoolKeyDefine.CreateCube, this.gameObject);

 

3).清理对象池

 AssetMgr.GetInstance().ClearPoolByKey(PoolKeyDefine.CreateCube);

 

4).查询对象池缓存情况

int poolNum = AssetMgr.GetInstance().GetResPoolObjCount(PoolKeyDefine.CreateCube);

 

真的很希望wx团队能开发一个可以贴代码的编辑法,尝试了好多方式都没法排版只能图片了

最后是小菜的一个demo展示:

    对于对象池的再进一步的包装也可以在预加载的时候完成一些事情,用loading来解决一些用户流畅性上的体验。甚至是加入池子中对象的数量判断,当缓存对象大于某个阈值时清理一部分(避免内存的占用过高),毕竟对象池也不是万能的,也是以内存的开销为代价的。

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Unity中,虽然没有内置的对象池类,但是可以通过自定义脚本来实现对象池的功能。下面是一个简单的示例代码,展示了如何创建一个基本的对象池: ```csharp using System.Collections.Generic; using UnityEngine; public class ObjectPool : MonoBehaviour { public GameObject prefab; // 预制体 public int poolSize; // 对象池大小 private List<GameObject> objectPool; void Start() { objectPool = new List<GameObject>(); for (int i = 0; i < poolSize; i++) { GameObject obj = Instantiate(prefab); obj.SetActive(false); objectPool.Add(obj); } } public GameObject GetObjectFromPool() { for (int i = 0; i < objectPool.Count; i++) { if (!objectPool[i].activeInHierarchy) { objectPool[i].SetActive(true); return objectPool[i]; } } // 如果对象池中没有可用对象,则动态创建一个新对象 GameObject newObj = Instantiate(prefab); objectPool.Add(newObj); return newObj; } public void ReturnObjectToPool(GameObject obj) { obj.SetActive(false); } } ``` 在上述代码中,我们创建了一个名为ObjectPool的脚本。在Start方法中,我们初始化了对象池,根据poolSize的值来创建一定数量的对象,并将它们存储在objectPool列表中。 GetObjectFromPool方法用于从对象池中获取一个可用的对象。我们遍历objectPool列表,寻找第一个处于非激活状态的对象,并将其设置为激活状态,然后返回该对象。如果对象池中没有可用对象,则动态创建一个新对象,并将其添加到objectPool列表中。 ReturnObjectToPool方法用于将使用完的对象返回到对象池中。我们将传入的对象设置为非激活状态,以便下次复用。 通过这样的自定义脚本,你可以在Unity中实现对象池的功能,以提高游戏的性能和效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值