欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Unity3D 对象池工具类

程序员文章站 2022-07-13 15:01:57
...

Unity3D 对象池工具类

注意右上角的Hierarchy面板中的对象生成与销毁时通过**与非**实现的, 替代了频繁的生成实例与销毁,

对象池优化前言

我们都知道在游戏中,如果我们想使用一个对象,第一步就是New一个对象出来,那么在Unity中是如何处理这些对象的呢,一般要游戏中,如果某一个对象跟其他的任何对象都没有关联,我们就可以认为这个对象是垃圾对象,是占用内存空间的,而在C#中有自己的处理垃圾内存的方式——CG垃圾自动回收机制,在垃圾自动回收机制处理垃圾之外还有一种方式是析构法来处理垃圾。

但是如果频繁的创建销毁对象,对CPU的运算消耗是相当大的,比如在制作FPS类型的游戏时,某种机枪可能一秒数十发的子弹,甚至在某些情况对象在瞬间的生成和销毁的数量将会十分恐怖,如果极为恐怖的数量不断的被生成和销毁,那么就会对性能的消耗将会十分恐怖,导致游戏卡顿甚至闪退。

一个设备影响游戏开发的硬件也就CPU、GPU和内存,我们可以针对这些硬件的有效利用,和降低运算速率来入手。

而对象池就是针对大量相同的对象重复调用,避免大量对象的生成销毁而存在的。

Unity3D 对象池工具类

对象池原理

通过集合的方式来存入生成的对象作为对象池,不断调用这个集合里的对象,通过将这些对象不断设为**与未**的方式即可。

将会用到两个集合:

游戏对象池结构:Dictionary<string, List<GameObject>> -->通过键值对的形式可以获取到存在集合中的对象

预制体资源结构:Dictionary<string, GameObject>> -->通过键值对的形式可以获取到在集合中存储的预制体

为了方便使用我封装的一个很便捷的对象池工具类供大家使用

对象池工具类框架

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public delegate void ObjectOperation(GameObject obj);

public class ObjectPool01 {
    #region 单例模式
    /// <summary>
    /// 设置单例
    /// </summary>
    private static ObjectPool01 instance;

    /// <summary>
    /// 获取单例
    /// </summary>
    /// <returns></returns>
    public static ObjectPool01 GetInstance(string loadPath = "") {
        if (instance == null) {
            if (loadPath != "") {
                instance = new ObjectPool01(loadPath);
            }else {
                instance = new ObjectPool01();
            }
        }
        return instance;
    }
    #endregion

    #region 对象池
    /// <summary>
    /// 对象池
    /// </summary>
    private Dictionary<string, List<GameObject>> pool;
    /// <summary>
    /// 需要使用的预设体
    /// </summary>
    private Dictionary<string, GameObject> prefabs;
    /// <summary>
    /// 加载预设体的路径
    /// </summary>
    private  string loadPrefabPath;

    /// <summary>
    /// 对象操作的委托
    /// </summary>
    public ObjectOperation objOperation;

    /// <summary>
    /// 构造函数
    /// </summary>
    private ObjectPool01() {
        //初始化
        pool = new Dictionary<string, List<GameObject>>();
        prefabs = new Dictionary<string, GameObject>();
    }

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="prefabPath"></param>
    private ObjectPool01(string prefabPath) {
        loadPrefabPath = prefabPath;
        Debug.Log(loadPrefabPath);
        pool = new Dictionary<string, List<GameObject>>();
        prefabs = new Dictionary<string, GameObject>();
    }

    /// <summary>
    /// 回收对象到对象池
    /// </summary>
    /// <param name="obj"></param>
    public  void RecycleObject(GameObject obj) {
        //取消对象的**
        obj.SetActive(false);
        //子对象池的名字
        string subPoolName = obj.name.Replace("(Clone)", "");
        //查看是否有该子对象池
        if(pool.ContainsKey(subPoolName)) {
            //添加到子池
            pool[subPoolName].Add(obj);
        }else {
            //新建池并添加对象到新的子对象池
            pool.Add(subPoolName,new List<GameObject>() { obj });
        }
    }

    /// <summary>
    /// 从对象池中生成对象.
    /// </summary>
    /// <returns></returns>
    public GameObject SpawnObject(string objName) {
        //返回的结果
        GameObject result = null;
        //判断有无此对象池
        if (pool.ContainsKey(objName)) {
            //子对象池是否是空的
            if(pool[objName].Count != 0){
                //获取子池中的第一个对象
                result = pool[objName][0];
                //从对象池中移除
                pool[objName].RemoveAt(0);
            }
        }
        //需要新建对象
        if(result == null) {
            if (!prefabs.ContainsKey(objName)) {
                //加载预制体
                prefabs.Add(objName, Resources.Load<GameObject>(loadPrefabPath + objName));
            }

            //获取到了新生成的对象
            result = UnityEngine.Object.Instantiate(prefabs[objName]);
        }
        //**对象
        result.SetActive(true);
        //设置位置
        result.transform.position = Vector3.one * 1000;
        //执行委托
        if(objOperation!=null) {
            objOperation(result);
        }
        //返回对象
        return result;
    }

    #endregion

}

生成对象

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Demo : MonoBehaviour {

    private RaycastHit hit;
	// Use this for initialization
	void Start () {
		
	}
	
	// Update is called once per frame
	void Update () {
        if (Input.GetMouseButtonDown(0))
        {
            //获取射线
            Ray r = Camera.main.ScreenPointToRay(Input.mousePosition);
            if(Physics.Raycast(r,out hit))
            {
                //赋值事件
                ObjectPool01.GetInstance("Prefabs/").objOperation =ObjOp;
                //获取对象
                ObjectPool01.GetInstance("Prefabs/").SpawnObject("Sphere");

            }
        }
	}

    /// <summary>
    /// 写逻辑,维护接口
    /// </summary>
    /// <param name="obj"></param>
    void ObjOp(GameObject obj)
    {
        obj.transform.position = hit.point;
    }
}

对象回收

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class AutoRecycle : MonoBehaviour {

	
    /// <summary>
    /// 对象的生成是取消其**, OnEnable 来替代Start
    /// </summary>
	void OnEnable () {
        StartCoroutine(Recycle());
	}

    IEnumerator Recycle()
    {
        yield return new WaitForSeconds(1.5f);
        ObjectPool01.GetInstance().RecycleObject(gameObject);
    }
}