對象池:對象存儲在一個池子中,當需要再次使用時取出,而不需要每次都實例化一個新的對象,將對象循環利用起來。當我們需要大量實例化對象時可采用對象池,如游戲中的子彈等物體,當我們玩射擊類游戲時,要發射大量子彈,如果每發子彈直接通過Instantiate全部實例化(筆者在unity中試過大量Instantiate后不銷毀,unity引擎直接崩潰了),當然還有打怪類游戲,小怪的生成等。
下面有個小例子
對象池腳本(單例腳本)主要有以下三個部分
1、創建一個集合,當做你的對象池,用來存儲對象
2、一個取對象的方法
3、一個存對象的方法
一、創建一個對象池腳本ObjectPools,將腳本設置成單例(單例在Unity中經常使用到),不用掛在任何物體上
注:集合中Add(),添加后,自動添加在集合末尾 Remove()刪除元素時,假設刪除第一個元素,集合中的元素自動向前補位(詳情看另一篇集合泛型)
1 public class ObjectPools : MonoBehaviour { 2 //創建集合作為對象池 3 List<GameObject> pools = new List<GameObject>(); 4 //單例 5 private static ObjectPools instance; 6 private ObjectPools() { } 7 public static ObjectPools GetInstance() 8 { 9 if (instance==null) 10 { 11 //創建一個名字為ShellPool的對象,並將單例腳本附上 12 instance = new GameObject("ShellPool").AddComponent<ObjectPools>(); 13 } 14 return instance; 15 16 } 17 //從對象池中取對象 18 public GameObject MyInstantiate(GameObject name) 19 { 20 //對象池中沒有對象 實例化對象 21 if (pools.Count==0) 22 { 23 return Instantiate(name, Vector3.zero, Quaternion.identity) as GameObject; 24 } 25 else 26 { 27 //如果池中有對象 取出第一個 28 GameObject go = pools[0]; 29 //將對象設置激活狀態 30 go.SetActive(true); 31 //從對象池中刪除對象 32 pools.Remove(go); 33 return go; 34 35 } 36 } 37 //向對象池存對象 38 public void DelayInstantiate(GameObject name) 39 { 40 //隱藏對象 41 name.SetActive(false); 42 //放入對象池中(集合中) 43 pools.Add(name); 44 } 45 }
二、創建一個GameManager腳本,控制物體生成(預制體放在Resources文件下)
1 public class GameManager : MonoBehaviour { 2 GameObject shellPrefab; 3 public void Awake() 4 { 5 //找到預制體 6 shellPrefab = Resources.Load("Part01/Prefabs/Shell") as GameObject; 7 } 8 private void Update() 9 { 10 if (Input.GetMouseButtonDown(0)) 11 { 12 //實例化對象 13 ObjectPools.GetInstance().MyInstantiate(shellPrefab); 14 } 15 } 16 }
三、預制體腳本,掛在預制體上,控制子彈向前
1 public class Shell : MonoBehaviour { 2 Transform target; 3 private void OnEnable() 4 { 5 //找到要生成的對象的空物體 位置,將空物體位置賦給對象初始位置 6 target = GameObject.Find("GameBullet").transform; 7 transform.position = target.position; 8 //啟動協程 延時兩秒 9 StartCoroutine(DelayObject(2f)); 10 } 11 private void Update() 12 { 13 //物體移動 14 transform.Translate(Vector3.forward * Time.deltaTime * 10); 15 } 16 //協程 17 IEnumerator DelayObject(float time) 18 { 19 yield return new WaitForSeconds(time); 20 //調用腳本 向對象池存對象 21 ObjectPools.GetInstance().DelayInstantiate(gameObject); 22 } 23 24 }
小結:對象池創建一部分對象,使用對象后,不銷毀對象,通過隱藏對象,讓人感覺被銷毀,待下次需要繼續使用時,通過激活之前被隱藏的對象,減少了實例化消耗內存的缺點。但因為創建對象后,對象只是隱藏,未被銷毀,在運行時,還是可能占用大量內存。