一、unity3D物件池————單個物件在池中的建立
阿新 • • 發佈:2018-12-27
物件池:物件儲存在一個池子中,當需要再次使用時取出,而不需要每次都例項化一個新的物件,將物件迴圈利用起來。當我們需要大量例項化物件時可採用物件池,如遊戲中的子彈等物體,當我們玩射擊類遊戲時,要發射大量子彈,如果每發子彈直接通過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 }
小結:物件池建立一部分物件,使用物件後,不銷燬物件,通過隱藏物件,讓人感覺被銷燬,待下次需要繼續使用時,通過啟用之前被隱藏的物件,減少了例項化消耗記憶體的缺點。但因為建立物件後,物件只是隱藏,未被銷燬,在執行時,還是可能佔用大量記憶體。