1. 程式人生 > >一、unity3D物件池————單個物件在池中的建立

一、unity3D物件池————單個物件在池中的建立

 

物件池:物件儲存在一個池子中,當需要再次使用時取出,而不需要每次都例項化一個新的物件,將物件迴圈利用起來。當我們需要大量例項化物件時可採用物件池,如遊戲中的子彈等物體,當我們玩射擊類遊戲時,要發射大量子彈,如果每發子彈直接通過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 }

 

小結:物件池建立一部分物件,使用物件後,不銷燬物件,通過隱藏物件,讓人感覺被銷燬,待下次需要繼續使用時,通過啟用之前被隱藏的物件,減少了例項化消耗記憶體的缺點。但因為建立物件後,物件只是隱藏,未被銷燬,在執行時,還是可能佔用大量記憶體。