本文主要是介绍Unity 性能优化之写个简单的缓存池,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
在公司看源码的时候,发现一个投篮的场景中,玩家把篮球不断投出去,然后不断的创建和销毁对象。于是试着写个缓存池来管理。
有个叫PoolManager的工具类插件可以很方便的实现,可以看这里的介绍Unity3D研究院之初探PoolManager插件。
但是其实对象池就是预先创建一点对象,当我们需要用的时候,去拿就行了。如果没有,再创建。使用完毕后也并不销毁,方便下次使用。有点类似于Android中的listview的holder。看起来并不难,花了点时间写了个。
BufferPoolList.cs
using UnityEngine;
using System.Collections;
using System.Collections.Generic;public class BufferPoolList{private List<GameObject> pool;private GameObject prefab;private Transform prefabParent;public BufferPoolList(GameObject obj, Transform parent, int count){prefab = obj;pool = new List<GameObject>(count);prefabParent = parent;for (int i = 0; i < count; i++){GameObject objClone = GameObject.Instantiate(prefab) as GameObject;objClone.transform.parent = prefabParent;//为克隆出来的子弹指定父物体objClone.name = "Clone0" + i.ToString();objClone.SetActive(false);pool.Add(objClone); }}public GameObject GetObject(){//遍历缓存池 找空闲的物体foreach (GameObject iter in pool){if (iter.activeSelf == false){iter.transform.SetParent(prefabParent);iter.SetActive(true);return iter;}}GameObject newPrefab = GameObject.Instantiate(prefab) as GameObject;newPrefab.transform.SetParent(prefabParent);newPrefab.name = "Clone0" + pool.Count.ToString();newPrefab.SetActive(true);pool.Add(newPrefab);return newPrefab;}
}
在Player上的脚本或者控制类脚本上初始化之后,需要使用我们初始化的物体时,只需要GetObject()即可,用完将物体设置不可见即可。可以在实例化的物体上判断物体是否超出屏幕边界,超出 则 .SetActive(false);设置物体不可见。
这样写虽然不用每次都创建对象,缓存池的目的算是达到了,但是每次获取可用对象时都去做个循环,总感觉怪怪的。所以换种写法,不用list,改用 Queue 队列来写。代码如下:
BufferPool.cs
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class BufferPool
{private Queue<GameObject> pool;private GameObject prefab;private Transform prefabParent; //使用构造函数构造对象池public BufferPool(GameObject obj,Transform parent,int count){prefab = obj;pool = new Queue<GameObject>(count);prefabParent = parent;for (int i = 0; i < count; i++){GameObject objClone = GameObject.Instantiate(prefab) as GameObject;objClone.transform.parent = prefabParent;//为克隆出来的子弹指定父物体objClone.name = "Clone0" + i.ToString();objClone.SetActive(false);pool.Enqueue(objClone); }}public GameObject GetObject(){GameObject obj = null;if (pool.Count > 0){obj = pool.Dequeue(); //Dequeue()方法 移除并返回位于 Queue 开始处的对象obj.transform.position = prefabParent.position;}else{obj = GameObject.Instantiate(prefab) as GameObject;obj.transform.SetParent(prefabParent);}obj.SetActive(true);return obj;}//回收对象public void Recycle(GameObject obj){obj.SetActive(false);pool.Enqueue(obj);//加入队列}
}
这样获取对象时,就不用做循环了。每次使用时,出列。实例化的物体不再使用时,再让他加入队列。这样也有个不方便的地方,需要在游戏物体的脚本上,拿到 Player上的 BufferPool.cs 脚本 ,来回收对象,因为获取对象时,已经把该实例给移出队列了,所以当不再使用时,必须调用Recycle方法来将其加入到队列中去。
虽然一个用的List ,一个用的 Queue,但是道理是一样的。目的也都是为了解决Unity实例化对象慢的问题。
链接:http://539go.com/2016/11/10/Unity-%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96%E4%B9%8B%E5%86%99%E4%B8%AA%E7%AE%80%E5%8D%95%E7%9A%84%E7%BC%93%E5%AD%98%E6%B1%A0/
这篇关于Unity 性能优化之写个简单的缓存池的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!