Unity 对象池(Object Pooling)理解与简单应用
2017-05-11 10:38
671 查看
Unity 对象池理解与简单应用
参考Unity官方教程 : Object PoolingUnity官方教程: Space Shooter
Github项目(使用对象池):Space Shooter
Github项目(封装对象池):GentleTank
对象池用于减少内存开销,其原理就是把可能用到到的对象,先存在一个地方(池),要用的时候就调出来,不用就放回去。而不是要用的时候创建,不用的时候销毁。
举个例子:
我有个飞机,射击子弹,按传统的方法就是,创建子弹,子弹击中目标或出界等销毁子弹。就是不断的创建与销毁,要知道创建和销毁是要消耗许多内存以及时间的。如果把子弹存在一个地方(池),需要子弹时,就从里面拿出来,不需要的时候放回去。
如果还有多个飞机,可以公用一个子弹库。
这个方法虽然一直保持着存储子弹空间的一个最大值,但相比不断创建与销毁的代价,是非常值得考虑的。
而实际开发中,可以按照需要适当放大或缩小池大小。
关于线程池还有连接池其原理类似对象池,不做介绍。
对象池简单应用
拿上面说的飞机射子弹的例子,上代码。子弹对象池类
using System.Collections.Generic; using UnityEngine; public class BulletsPool : MonoBehaviour { public static BulletsPool bulletsPoolInstance; //子弹池单例 public GameObject bulletObj; //子弹perfabs public int pooledAmount = 5; //子弹池初始大小 public bool lockPoolSize = false; //是否锁定子弹池大小 private List<GameObject> pooledObjects; //子弹池链表 private int currentIndex = 0; //当前指向链表位置索引 void Awake() { bulletsPoolInstance = this; //把本对象作为实例。 } void Start() { pooledObjects = new List<GameObject>(); //初始化链表 for (int i = 0; i < pooledAmount; ++i) { GameObject obj = Instantiate(bulletObj); //创建子弹对象 obj.SetActive(false); //设置子弹无效 pooledObjects.Add(obj); //把子弹添加到链表(对象池)中 } } public GameObject GetPooledObject() //获取对象池中可以使用的子弹。 { for (int i = 0; i < pooledObjects.Count; ++i) //把对象池遍历一遍 { //这里简单优化了一下,每一次遍历都是从上一次被使用的子弹的下一个,而不是每次遍历从0开始。 //例如上一次获取了第4个子弹,currentIndex就为5,这里从索引5开始遍历,这是一种贪心算法。 int temI = (currentIndex + i) % pooledObjects.Count; if (!pooledObjects[temI].activeInHierarchy) //判断该子弹是否在场景中激活。 { currentIndex = (temI + 1) % pooledObjects.Count; return pooledObjects[temI]; //找到没有被激活的子弹并返回 } } //如果遍历完一遍子弹库发现没有可以用的,执行下面 if(!lockPoolSize) //如果没有锁定对象池大小,创建子弹并添加到对象池中。 { GameObject obj = Instantiate(bulletObj); pooledObjects.Add(obj); return obj; } //如果遍历完没有而且锁定了对象池大小,返回空。 return null; } }
自动发射子弹类
using UnityEngine; public class AutoFire : MonoBehaviour { //传统创建子弹方法需要的子弹perfabs //public GameObject shotObj; public GameObject shotSpawn; //子弹发射的初始化位置 public float fireRate = 0.2f; //每次发射子弹事件间隔 private float nextFire; //下一次发射子弹的时间 void Update() { if (Time.time > nextFire) //可以发射子弹时间 { nextFire = Time.time + fireRate; //传统创建子弹方法 //Instantiate(shotObj, shotSpawn.transform.position, shotSpawn.transform.rotation); //获取对象池中的子弹 GameObject bullet = BulletsPool.bulletsPoolInstance.GetPooledObject(); if(bullet != null) //不为空时执行 { bullet.SetActive(true); //激活子弹并初始化子弹的位置 bullet.transform.position = shotSpawn.transform.position; } } } }
子弹失效,回收子弹类
判断是否出界,这个类是放在场景的一个长方体里,飞机子弹都在这长方体内,所以时刻都是与这个长方体碰撞中的,当子弹出界,及子弹碰撞结束。这是Unity官方教程(Space shooter)里有的。
using UnityEngine; public class DestroyByBoundary : MonoBehaviour { void OnTriggerExit(Collider other) { //Destroy(other.gameObject); //传统方法,直接删除子弹 other.gameObject.SetActive(false); //对象池方法,把子弹失效就好了 } }
刚开始,如图已经发了三发Bolt1,对象池中还有两发active是false的:
当稳定后,子弹池稳定在7发。
进阶
见 Github:GentleTank/Assets/GameControl/Object%20Pool/Scripts/ObjectPool.cs将对象池封装成ScriptObject。
将对象池重新封装,做成一个ScriptObject,就可把对象池抽象出来,就可以应用于任何物体。
在上图右下角Project面板上创建一个对象池文件。
其面板如下。
注意:使用前需要调用CreateObjectPool(),来初始化创建对象池。
相关文章推荐
- xargs的理解与简单应用
- 简单理解static_cast, dynamic_cast, reinterpret_cast和const_cast的区别和应用
- WEB应用中context上下文的简单理解
- 转载:Java中关于三目运算符理解和简单应用.
- AJAX GET与POST区别及web离线应用的简单理解
- 一个新人对于JavaScript简单应用的理解
- unity 委托事件简单应用
- Hololens入门之使用Unity开发一个简单的应用
- Unity IOC容器的简单应用
- 黑马程序员 贪心法则的应用及简单理解
- 快速排序的简单应用及回调函数的初步理解
- Spring AOP 简单理解及应用
- 关于Unity中joint的简单理解
- unity 简单编辑器的扩展应用—1
- 对象池的应用的简单Demo
- 简单理解ThreadLocal原理和适用场景,多数据源下ThreadLocal的应用
- 关于Spring Boot 的一些简单理解和应用
- 关于数据库中FK的简单理解以及应用
- WWW在unity中的简单应用实践
- Java中关于三目运算符理解和简单应用.