U3D之对象缓冲池技术

    xiaoxiao2025-05-24  12

    U3D对象缓冲池技术

    当我们创建对象的时候,比如我们可能通过以下三种方法:

    GameObject cube= new GameObject("Cube"); GameObject.Instantiate("预制体"); GameObject.CreatePrimitive(PrmitiveType.XXX);

    通过着这种方法创建的物体需要通过Destroy进行销毁,在一个游戏中对于一些需要频繁创建销毁的物体如:特效,子弹等,就要进行不断地创建和销毁工作,这会造成游戏极大的开销,所以我们通过对象缓冲池技术来对这一部分性能进行优化。 U3D提供了专门进行对象池技术的插件:Unity3D PoolManager缓冲池插件 - 杨名天吓 - 博客 https://blog.csdn.net/henren555/article/details/42100881 这里我要讲的是自己实现的对象缓冲池技术。 对象池的本质:所谓的对象缓冲池实际上是通过将频繁使用的物体如子弹等预制体事先放置在一个字典容器中(池),使用的时候在池中通过Key进行查找,如果存在则将其提取出来,并将其active设为true,然后更改它的位置;当子弹失效大的时候我们不去销毁它,而是将其状态置为false,并将其重新放入字典池中。 代码结构为: Pool.cs:总池,保存不同类型的物体; SubPool.cs:每一种物体分属一个subpool,该物体可能有许多个,都加入到subpool的 容器中 sendmessage函数:通过调用sendmessage函数中的函数,来更新新激活的物体位置 通过Pool找到subpool,通过subpool找到需要的物体

    //Pool.cs using System; using System.Collections.Generic; using System.Linq; using System.Text; using UnityEngine; /// <summary> /// 游戏对象池,所有类型的对象都由此管理器管理 /// 主要使用两个方法spawn和unSpawn /// </summary> public class Pool:SingletonMono<Pool>//单例模式 { //protected override void Awake() //{ // base.Awake();//千万别漏掉 //} //子对象池分类(子弹,怪物,特效等) Dictionary<string, SubPool> dicPools = new Dictionary<string, SubPool>(); /// <summary> /// 创建缓冲池对象 /// </summary> /// <param path="path">预制体路径,从Resource加载。路径是Resource文件夹下预制体的路径,如:GameObjectPool.Instance.spawn("NewPrefabs/bullet")</param> /// <returns></returns> public GameObject spawn(string path)//从池子中取对象 { if (!dicPools.ContainsKey(path))//如果没有子对象池 { createNewSubPool(path);//创建子对象池 } SubPool pool = dicPools[path];//获取子对象池 return pool.spawn(); } /// <summary> /// 回收缓冲池对象 /// </summary> /// <param name="go"></param> public void unSpawn(GameObject go)//回收对象 { SubPool pool = null; foreach (SubPool p in dicPools.Values) { if (p.contains(go)) { pool = p; break; } } if(pool!=null) { pool.unSpawn(go); } } public void unSpawnAll()//回收所有对象 { foreach (SubPool p in dicPools.Values) { p.unSpawnAll(); } } private void createNewSubPool(string path)//创建新的子对象池 { GameObject goPrefab = Resources.Load<GameObject>(path); SubPool curPool = new SubPool(goPrefab,transform); dicPools.Add(path, curPool);//对象池名字即是goPrefab名字 } } //subpool.cs using System; using System.Collections.Generic; using System.Linq; using System.Text; using UnityEngine; /// <summary> /// 子对象池,用于管理一类对象 /// /// </summary> public class SubPool { GameObject goPrefab;//预制体 Transform transParent;//空物体 List<GameObject> listObjects = new List<GameObject>();//子对象池中管理的所有对象 public SubPool(GameObject goPrefab, Transform transParent) { this.goPrefab = goPrefab; GameObject goParent = new GameObject(goPrefab.name);//根据预制体名字创建了一个空对象 goParent.transform.SetParent(transParent); this.transParent = goParent.transform; } /// <summary> /// 1:从容器中查找一个隐藏物体 /// 2:如果没有找到就克隆goPrefab预制体对象 /// </summary> /// <returns></returns> public GameObject spawn() { GameObject go = null; foreach (GameObject tmp in listObjects) { if (tmp!=null&&!tmp.activeSelf) { go = tmp; break; } } if (go == null)//在容器中如果没有找到 { //从资源中读取 go = GameObject.Instantiate<GameObject>(goPrefab); go.transform.parent = transParent; listObjects.Add(go); } go.SetActive(true);//显示游戏对象 Debug.Log("go name="+go.name); go.SendMessage("spawn", SendMessageOptions.DontRequireReceiver); return go; } public void unSpawn(GameObject go) { if (contains(go)) { go.SendMessage("unSpawn", SendMessageOptions.DontRequireReceiver); go.SetActive(false);//隐藏了游戏对象 } } public void unSpawnAll() { foreach (GameObject go in listObjects) { if (go.activeSelf) { unSpawn(go); } } } public bool contains(GameObject go) { return listObjects.Contains(go); } }

    使用的时候在原来创建物体的地方调用 GameObject go=Pool.Instance.spawn(prefabNames[randIndex]); 在本该销毁物体的地方调用 Pool.Instance.unSpawn(this.gameObject);

    最新回复(0)