在 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