Unity3D 官方对象池的使用。
对象池
对象池是一个可以复用对象的容器。
当需要创建对象时,调用对象池的接口获得对象。
当需要销毁对象时,调用对象池的接口归还对象。
而对象池会判断池子里是否有可用的对象,如果有,直接取出一个对象返回,如果没有,就创建一个新的对象。
从对象池里取出的对象,使用完毕之后要放回对象池。
通过复用对象,减少了创建和销毁对象的次数,避免因频繁创建和销毁对象带来的性能问题。
创建对象
下面来看看 Unity3D 官方提供的对象池类。
首先需要引用 UnityEngine.Pool
这个命名空间,然后使用 ObjectPool 这个类型定义一个成员字段,在 Start 中实例化,并提供一个用于创建对象的 OnCreate 函数,需要带有返回值,即创建好的新对象。
这里就简单地使用 GameObject.CreatePrimitive
创建一个 Cube。
在 Update 中,通过 cubePool.Get()
函数获得对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| using System.Collections; using System.Collections.Generic; using UnityEngine;
using UnityEngine.Pool;
public class ObjectPoolSample : MonoBehaviour { public ObjectPool<GameObject> cubePool;
Vector3 pos;
void Start() { cubePool = new ObjectPool<GameObject>(OnCreate); }
void Update() { if (Input.GetKeyDown(KeyCode.Alpha1)) { GameObject obj = cubePool.Get(); obj.transform.position = pos; pos += Vector3.right; } } GameObject OnCreate() { GameObject obj = GameObject.CreatePrimitive(PrimitiveType.Cube); return obj; } }
|
归还对象
目前只提供了创建对象的函数,还需要提供归还对象的函数。
添加一个 List,用于维护已创建的对象。
在实例化对象池时,第三个参数是归还对象时的回调函数 OnRelease,带有一个参数 GameObject obj,可以获取到被归还的对象,通过 SetActive(false)
把它隐藏。第二个参数暂时填 null。
然后在 Update 中添加一个按键 2 的逻辑,遍历 cubeList,把所有的对象都通过 cubePool.Release
归还,归还之前会调用 OnRelease 回调函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Pool;
public class ObjectPoolSample : MonoBehaviour { public List<GameObject> cubeList;
void Start() { cubePool = new ObjectPool<GameObject>(OnCreate, null, OnRelease); cubeList = new List<GameObject>(); }
void Update() { if (Input.GetKeyDown(KeyCode.Alpha1)) { GameObject obj = cubePool.Get(); cubeList.Add(obj); } else if (Input.GetKeyDown(KeyCode.Alpha2)) { for (int i = 0; i < cubeList.Count; i++) { cubePool.Release(cubeList[i]); } cubeList.Clear(); } }
void OnRelease(GameObject obj) { obj.SetActive(false); } }
|
再次获得对象
因为在 OnRelease 函数中,隐藏了对象,此时对象池中存有的对象都是隐藏的,所以取出的对象都是隐藏的。
刚开始因为对象池内是空的,所以每次调用 cubePool.Get()
时,都会调用 OnCreate 函数。
但是当对象池不为空时,就不会再去调用 OnCreate 函数,而是调用另一个回调函数(也就是实例化对象池时,暂时填 null 的那个参数)。
所以还需要提供一个获得对象时的回调函数 OnGet,在这个函数中通过 SetActive(true)
把它显示出来。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Pool;
public class ObjectPoolSample : MonoBehaviour {
void Start() { cubePool = new ObjectPool<GameObject>(OnCreate, OnGet, OnRelease); }
void OnGet(GameObject obj) { obj.SetActive(true); }
}
|
效果图:
可以看到,空池时,创建了三个 Cube,归还给对象池之后,再次获得三个 Cube,都是复用之前创建好的。

销毁对象
当对象池最大容量已满,归还的对象是不会被存入对象池的,而是调用一个被销毁的回调函数。
主动调用 Clear 函数,也会为池内的所有对象都调用一次被销毁的回调函数。
此时可以提供一个 OnObjectDestroy 函数作为对象销毁时的回调函数(OnDestroy 是脚本的生命周期函数,需要换个名字避免冲突)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Pool;
public class ObjectPoolSample : MonoBehaviour {
void Start() { cubePool = new ObjectPool<GameObject>(OnCreate, OnGet, OnRelease, OnObjectDestroy); } void Update() { else if (Input.GetKeyDown(KeyCode.Alpha3)) { cubePool.Clear(); } }
void OnObjectDestroy(GameObject obj) { Debug.Log($"销毁对象 {obj.name} pos = {obj.transform.position}"); Destroy(obj); } }
|
效果图:
按键 1 创建三个 Cube,按键 2 归还所有 Cube,按键 3 销毁池内所有对象。

完整代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
| using System.Collections; using System.Collections.Generic; using UnityEngine;
using UnityEngine.Pool;
public class ObjectPoolSample : MonoBehaviour { public ObjectPool<GameObject> cubePool;
public List<GameObject> cubeList; Vector3 pos;
void Start() { cubePool = new ObjectPool<GameObject>(OnCreate, OnGet, OnRelease, OnObjectDestroy); cubeList = new List<GameObject>(); }
void Update() { if (Input.GetKeyDown(KeyCode.Alpha1)) { GameObject obj = cubePool.Get(); obj.transform.position = pos; pos += Vector3.right; cubeList.Add(obj); } else if (Input.GetKeyDown(KeyCode.Alpha2)) { for (int i = 0; i < cubeList.Count; i++) { cubePool.Release(cubeList[i]); } cubeList.Clear(); } else if (Input.GetKeyDown(KeyCode.Alpha3)) { cubePool.Clear(); } }
GameObject OnCreate() { GameObject obj = GameObject.CreatePrimitive(PrimitiveType.Cube); return obj; }
void OnGet(GameObject obj) { obj.SetActive(true); }
void OnRelease(GameObject obj) { obj.SetActive(false); }
void OnObjectDestroy(GameObject obj) { Debug.Log($"销毁对象 {obj.name} pos = {obj.transform.position}"); Destroy(obj); } }
|