Unity对象池管理 Demo展示
逻辑 在游戏中会出现大量重复的物体需要频繁的创建和销毁;比如子弹,敌人,成就列表的格子等;
频繁的创建删除物体会造成很大的开销,像这种大量创建重复且非持续性保持作用的对象 我们会使用对象池将其管理起来,用空间换效率;
对象池的要对外提供创建销毁对象的接口,已经添加对象池的接口;
对内要提供创建对象,根据路径查找预制的接口;
整体逻辑如下:
加载/添加对象池 添加资源路径,分为Resources文件夹下和SteamingAssets文件下资源;
Resources加载时路径不需要后缀,SteamingAssets需要后缀,根据path路径开头的判断加载方式,同时对路径做处理;
SteamingAssets需要根据平台添加路径头Application.streamingAssetsPath;
Resources需要去掉格式后缀,如.perfab;
这里我测试只使用Resources路径,正式项目自行处理;
存放预创建好的对象:
1 private Dictionary<string ,List<GameObject>> pool;
存放预制体路径:
1 private Dictionary<string , string > objPath;
1 2 3 4 5 6 public void InitPath (){ objPath.Add("cube" ,"Cube" ); objPath.Add("sphere" ,"Sphere" ); }
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 public void Add (string key, int num ){ if (pool.ContainsKey(key)) { for (int i = 0 ; i < num; ++i) { GameObject go = Instantiate(Resources.Load<GameObject>(objPath[key])); go.SetActive(false ); pool[key].Add(go); } } else { List<GameObject> goList = new List<GameObject>(); pool.Add(key, goList); for (int i = 0 ; i < num; ++i) { GameObject go = Instantiate(Resources.Load<GameObject>(objPath[key])); go.SetActive(false ); pool[key].Add(go); } } }
管理对象池 对象池管理需要对外提供创建对象,销毁对象,延迟销毁和清空池的方法;
创建对象时,需要提供key,坐标,旋转;
现查找是否有对象池,没有则添加;
这里提供了四元素和欧拉角的重载方法;
创建对象 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 public GameObject FindUsable (string key{ if (pool.ContainsKey(key )) { foreach (GameObject item in poo { if (!item.activeSelf) return item; } Debug.Log($"{key} 的对象池数量不够" ); } else { Debug.Log($"{key} 未添加对象池" ); } return null ; } public GameObject CreateObject (string k{ GameObject tempGo = FindUsable(key ) if (tempGo == null ) { Debug.Log($"{key} 的对象池数量不够" ); Add(key, 10 ); tempGo = FindUsable(key); } tempGo.transform.position = positio tempGo.transform.rotation = quatern tempGo.SetActive(true ); return tempGo; } public GameObject CreateObject (string k{ GameObject tempGo = FindUsable(key ) if (tempGo == null ) { Debug.Log($"{key} 的对象池数量不够" ); Add(key, 10 ); tempGo = FindUsable(key); } tempGo.transform.position = positio tempGo.transform.rotation = Quatern tempGo.SetActive(true ); return tempGo; }
销毁对象 延时销毁可使用回调(invoke)或协程;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public void Destory (GameObject destoryGo ){ destoryGo.SetActive(false ); } public void Destory (GameObject tempGo, float delay ){ StartCoroutine(DelayDestory(tempGo,delay)); } private IEnumerator DelayDestory (GameObject destoryGO, float delay ){ yield return new WaitForSeconds (delay ) ; Destory(destoryGO); }
清空池 1 2 3 4 5 6 7 8 9 10 public void Clear (string key ){ pool.Remove(key); } public void ClearAll (){ pool.Clear(); }
测试代码 两个按钮分别创建方块和球,每次创建更改一次位置;
鼠标射线点击延迟1s销毁;
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 public class Test : MonoBehaviour { public Button btnCube; public Button btnSphere; void Start () { GameObjectPool.I.InitPath(); GameObjectPool.I.Add("cube" ,10 ); GameObjectPool.I.Add("sphere" ,10 ); btnCube.onClick.AddListener(OnBtnCube); btnSphere.onClick.AddListener(OnBtnSphere); } private Vector3 deltaPos = new Vector3(1 , 1 , 1 ); private Vector3 pos =new Vector3(-10 ,0 ,0 ); private void OnBtnCube () { GameObject go = GameObjectPool.I.CreateObject("cube" , pos, Vector3.zero); go.transform.SetParent(null ); SceneManager.MoveGameObjectToScene(go, SceneManager.GetSceneByName("1" )); go.transform.position += deltaPos; pos = go.transform.position; } private Vector3 pos1 =new Vector3(0 ,0 ,0 ); private void OnBtnSphere () { GameObject go = GameObjectPool.I.CreateObject("sphere" , pos1, Vector3.zero); go.transform.SetParent(null ); SceneManager.MoveGameObjectToScene(go, SceneManager.GetSceneByName("1" )); go.transform.position += deltaPos; pos1 = go.transform.position; } private void Update () { if (Input.GetMouseButtonDown(0 )){ Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); RaycastHit hitInfo; if (Physics.Raycast(ray,out hitInfo)){ Debug.DrawLine(ray.origin,hitInfo.point); GameObject gameObj = hitInfo.collider.gameObject; Debug.Log("click object name is " + gameObj.name); GameObjectPool.I.Destory(gameObj,1 ); } } } }