对象池:对象存储在一个池子中,当需要再次使用时取出,而不需要每次都实例化一个新的对象,将对象循环利用起来。当我们需要大量实例化对象时可采用对象池,如游戏中的子弹等物体,当我们玩射击类游戏时,要发射大量子弹,如果每发子弹直接通过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 }

 

小结:对象池创建一部分对象,使用对象后,不销毁对象,通过隐藏对象,让人感觉被销毁,待下次需要继续使用时,通过激活之前被隐藏的对象,减少了实例化消耗内存的缺点。但因为创建对象后,对象只是隐藏,未被销毁,在运行时,还是可能占用大量内存。