你使用对象池了吗
什么是对象池?
对象池,简单的说就是一种为了避免重复创建,删除对象的解决方案。它可以通过复用游戏对象,一定程度上提高游戏性能,避免内存消耗,特别针对任何频繁创建删除对象的情景。这符合了性能优化中对脚本优化的理念。是居家旅行…哦不…游戏开发必备技能。
对象池的实现原理?
创建复用对象的集合,通过查找和设置集合元素的active状态,达到和创建、删除一样的视觉效果。
这里先通过一个射击子弹的简单例子,从不用对象池,到给子弹创建对象池,去繁就简的一步步呈现对象池使用过程,深化理解。
不用对象池的小白脚本
Control.cs
... public class Control:MonoBehaviour{ public GameObject bulletPrb; void Update(){ if(Input.GetMouseButton(0)) Fire(); } void Fire(){ Instantiate(bulletPrb); } }
Bullet.cs
... public class Bullet:Monobehaviour{ void Start(){ Invoke("Destroy",2); } void Destroy(){ Destroy(gameObject); } }
这里很容易的脑补出Hierarchry下,bullet对象一直在创建,销毁,创建,销毁。。。
使用对象池的一阶脚本
Control.cs
... using System.Collections.Generic; public class Control:MonoBehaviour{ public GameObject bulletPrb; public int poolingCapacity = 20; public List<GameObject> pool; void Start(){ //创建对象池,并将对象设为不可见 pool = new List<GameObject>() for(int i=0 ; i<poolingCapacity;i++) { GameObject bullet = Instantiate(bulletPrb); pool.Add(bullet); pool[i].SetActive(false); } } void Update(){ if(Input.GetMouseButton(0)) Fire(); } void Fire(){ //Instantiate(bulletPrb,transform.position,Quternion.identity); for(int i = 0 ; i < pool.Count; i++) { //自动搜索对象池中失活的对象并激活显示 if ( !pool[i].activeinHierarchy ) { pool[i].transform.position = transform.position; pool[i].transform.rotation = transform.rotation; pool[i].SetActive(true); break; } } } }
Bullet.cs
... public class Bullet:Monobehaviour{ void OnEnable(){ Invoke("Destroy",2); } void Destroy(){ //Destory(gameObject); gameObject.SetActive(false); //只要隐藏掉就好,对象还在对象池中 } void OnDisable{ CancelInvoke(); } }
这样对象池的功能算是实现了。然而它是被构建在控制脚本中的,这样显然不行。这就像编程小白把所有语句写在主函数中一样,这不符合面向对象的思想!因此,需要第三步
使用对象池的二阶脚本
新建一个ObjectBulletPool.cs 并挂载到新建的空物体ObjectPooler上
... using System.Collections.Generic public class ObjectPool: MonoBehaviour{ public static ObjectPool current; public GameObject objectPrb; //将被放入对象池中的预制体 public int poolCapacity = 20; public List<GameObject> pool; public bool willgrow = true; //池子容量不够时,是否自动扩展池子 void Awake(){ current = this; } void Start(){ for(int i = 0 ; i<poolCapacity ; i++) { GameObject obj = Instantiate(objectPrb); pool.Add(obj); obj.SetActive(false); } } public GameObject GetPooledObject(){ for( int i = 0 ; i<pool.Count ; i++) //遍历对象池,将未激活的对象传递出去 { if ( ! pool[i].activeInHierarchy ) return pool[i]; } if ( willgrow ) //当池子中所有对象都激活了,但是还想激活显示对象时,扩展池子 { GameObject obj = Instantiate(objectPrb); pool.Add(obj); obj.SetActive(false); return obj; } return null; } }
简化 Control.cs
... using System.Collections.Generic; public class Control:MonoBehaviour{ /* public GameObject bulletPrb; public int poolingCapacity = 20; public List<GameObject> pool; void Start(){ //创建对象池,并将对象设为不可见 pool = new List<GameObject>() for(int i=0 ; i<poolingCapacity;i++) { GameObject bullet = Instantiate(bulletPrb); pool.Add(bullet); pool[i].SetActive(false); } } */ void Update(){ if(Input.GetMouseButton(0)) Fire(); } void Fire(){ //Instantiate(bulletPrb,transform.position,Quternion.identity); /* for(int i = 0 ; i < pool.Count; i++) { //自动搜索对象池中失活的对象并激活显示 if ( !pool[i].activeinHierarchy ) { pool[i].transform.position = transform.position; pool[i].transform.rotation = transform.rotation; pool[i].SetActive(true); break; } } */ //获取未激活对象,激活显示 GameObject obj = ObjectPool.current.GetPooledObject(); if (obj == null) return; obj.transform.position = transform.position; obj.transform.rotation = transform.rotation; obj.SetActive(true); } }
不用改 Bullet.cs
... public class Bullet:Monobehaviour{ void OnEnable(){ Invoke("Destroy",2); } void Release(){ //Destory(gameObject); gameObject.SetActive(false); //只要隐藏掉就好,对象“回到”对象池中 } void OnDisable{ CancelInvoke(); } }
多说一句,如果你能发射不同类型的子弹怎么办?
解决思路:将子弹类型bulletPrb对象改成数组,在GetPooledObject()函数中传入子弹类型的参数,然后遍历数组匹配子弹类型,return出去。
小结:
这个对象池其实是固定的,一旦创建就不用删除,这样便于复用创建好的对象。使用对象其实就是在对象池中搜索没有active的对象并激活获取到它好进行操作。释放对象就是让他失活,好被以后搜索复用。
Ok,看到这里,对象池的基本用法就掌握了,在实际项目中需求会更加多变,但是万变不离本质。高阶运用也是从低阶进化的!
高阶运用请看这位老兄的文章:
unity中的通用对象池
原文地址:https://www.jianshu.com/p/60b228285c47
相关推荐
-
eShopOnWeb 知多少 C#
2019-5-13
-
sql注入风险,你有吗? C#
2019-8-30
-
十二个 ASP.NET Core 例子 C#
2019-6-30
-
Asp.Net Core&Docker部署到树莓派3B中 C#
2019-7-8
-
谈谈我的入门级实体框架Loogn.OrmLite C#
2019-5-12
-
.NET Core脚本工具dotnet-script C#
2019-5-5
-
surging 微服务引擎 2.0 会有多少惊喜? C#
2019-7-3
-
.Net微信网页开发之使用微信JS-SDK获取当前地理位置 C#
2019-9-2
-
C#如何在PDF文件添加图片印章 C#
2019-4-19
-
EFCore动态切换Schema C#
2019-4-20