对象池
在 Unity 的运行环境中创建或是释放(destroy)对象需要付出昂贵的代价。
例如:在飞机大战游戏中,当用户点击射击的时候,会创建很多“子弹”对象,当“子弹”对象碰到敌人时,会被销毁,只要用户一点击射击就会执行这样的逻辑
当然这是不可取的,因为第一句话告诉了我们不断的创建销毁对象时要付出昂贵的代价的,最好的做法,莫过于重用,怎么感觉扯上设计模式了,呵呵~
具体的做法如下:
把所有子弹存入一个列表中,当子弹对象碰到敌人时,我们不要对此子弹进行销毁Destory操作,而是设置此子弹为非激活状态,当用户第二次,或者第三次点击发射子弹的时候,
我们程序检测列表集合中有没有非激活状态的子弹,如果有,就激活重用他,只是此时需要随着飞机的位置而改变子弹发射的位置罢了
我们可以写一个通用的对象池脚本,代码如下:
1 public class NewObjectPooler : MonoBehaviour 2 { 3 public static NewObjectPooler current; 4 public GameObject pooledObject; 5 public int pooledAmount = 20; 6 public bool willGrow = true; 7 public List<GameObject> pooledObjects; 8 9 void Awake() 10 { 11 current = this; 12 } 13 14 void Start() 15 { 16 pooledObjects = new List<GameObject>(); 17 for (int i = 0; i < pooledAmount; i++) 18 { 19 GameObject obj = Instantiate(pooledObject) as GameObject; 20 obj.SetActive(false); 21 pooledObjects.Add(obj); 22 } 23 } 24 25 public GameObject GetPooledObject() 26 { 27 for (int i = 0; i < pooledObjects.Count; i++) 28 { 29 if (!pooledObjects[i].activeInHierarchy) 30 { 31 Debug.Log(i + "=" + pooledObjects[i].activeInHierarchy); 32 return pooledObjects[i]; 33 } 34 } 35 36 //表示是否不间断射击
//原理:上面的for循环是遍历对象列表,如果存在未激活的对象,就返回此对象,并激活它, 37 //如果对象列表上限为20的话,每个对象将在被激活后的2s被设置成隐藏状态,而Update方法是一帧一帧执行的,而一秒时间内可以执行n帧 38 //所以说上面的for循环有可能就在一秒内被执行完成了,也就是说20个对象将会在一秒内被激活,而对象的销毁时间为2s 39 //所以我们看到的景象是:第一秒产生20个对象,过一小段时间,又产生了20个对象,总会有个时间间隔,循环反复 40 //如果当上面的for循环没有一个返回值的时候,就会执行下面的代码,也就是说,当20个对象全部被返回,并且时间小于2s的这段时间内 41 //程序做的就是执行下面的代码,下面的代码就是在这段时间内产生对象并加入到对象列表里,当上面的for循环被激活了 42 //那么对象列表就不止20个了,同时下面的语句就再也不会被执行了,因为第一次willGrow被执行的时候,算的就是时间差范围内需要多少个对象
//此时,就看不到发射子弹而此时间隔了,而是子弹连续不断发射的场景
//具体差异请看下面的gif动画 43 if (willGrow) 44 { 45 GameObject obj = Instantiate(pooledObject) as GameObject; 46 pooledObjects.Add(obj); 47 return obj; 48 } 49 return null; 50 } 51 }
外部调用:
1 public class BulletFire : MonoBehaviour { 2 public float firetime = .05f; 3 void Start() 4 { 5 InvokeRepeating("Fire", firetime, firetime); 6 } 7 void Fire() 8 { 9 GameObject obj = NewObjectPooler.current.GetPooledObject(); 10 if (obj == null) return; 11 obj.transform.position = new Vector3(0, -1f, 0); 12 obj.transform.rotation = Quaternion.identity; 13 obj.SetActive(true); 14 } 15 }
对象的”伪销毁“代码:
1 public class BulletDestory : MonoBehaviour 2 { 3 void OnEnable() 4 { 5 Invoke("Destroy", 2f); 6 } 7 void Destroy() 8 { 9 gameObject.SetActive(false); 10 } 11 void OnDisable() 12 { 13 CancelInvoke(); 14 } 15 }
willGrow:
True False
参考:http://unity3d.com/learn/tutorials/modules/beginner/live-training-archive/object-pooling