Unity框架_对象池

对象池的目的:

减少内存分配和垃圾回收: 创建和销毁游戏对象需要分配和释放内存,而频繁的内存分配和垃圾回收可能导致性能问题和帧率下降。通过使用对象池,您可以预先创建一组对象,并在需要时重复使用它们,从而减少了内存分配和垃圾回收的负担。

提高创建速度: 对象池避免了创建新对象的开销,因为您可以重复使用已经存在于池中的对象。这可以显著提高游戏对象的创建速度,尤其是在需要频繁创建和销毁对象的情况下,例如生成粒子、敌人、子弹等。

为了更好的理解抽象的概念 我将对象池(List)喻为抽屉 用衣柜(字典)存储这些所有的抽屉(对象池)

对象池也分不同的类型 比如游戏中的子弹是一种类型,特效是一种类型,敌人,粒子等等

这些不同类型的对象都需要不同的对象池来存储  所以我用Lsit存储这些单个类型对象池s

字典存放所有类型的对象池

首先 先构建一个存放对象的对象池,也就是抽屉List

/// <summary>
/// 抽屉 单个类型对象的对象池
/// </summary>
public class PoolData
{
    //抽屉父对象 窗口中管理抽屉中所有的子对象
    public GameObject fatherObj;
    public List<GameObject> poolList;

    /// <summary>
    /// 创建一个新的抽屉(对象池),并设置窗口面板层级关系
    /// </summary>
    /// <param name="obj"></param>
    /// <param name="poolObj"></param>
    public PoolData(GameObject obj, GameObject poolObj)
    {
        fatherObj = new GameObject(obj.name);
        fatherObj.transform.parent = poolObj.transform;
        //抽屉容器 用于存放抽屉里的对象
        poolList = new List<GameObject>() { obj };
        //将对象添加到List当中
        PushObj(obj);
    }

    //往抽屉里添加对象
    public void PushObj(GameObject obj)
    {
        //先失活
        obj.SetActive(false);
        poolList.Add(obj);
        obj.transform.parent = fatherObj.transform;
    }

    //从抽屉中取出对象
    public GameObject GetObj()
    {
        GameObject obj = null;
        //取出第一个
        obj = poolList[0];
        obj.SetActive(true);
        poolList.RemoveAt(0);
        //中断父子关系
        obj.transform.parent = null;

        return obj;
    }

}

柜子(字典) 用于存放和管理所有类型的对象池

/// <summary>
/// 柜子
/// </summary>
public class Pool : SingletonAutoMono<Pool>
{

    //对象池容器(柜子) 存储所有类型的对象池(抽屉)
    public Dictionary<string, PoolData> poolDic = new Dictionary<string, PoolData>();
    //对象池 窗口管理(柜子) 父对象
    private GameObject poolObj;

    /// <summary>
    /// 得到对应类型对象池中的对象
    /// </summary>
    /// <param name="name">对象池的名字/对象名</param>
    /// <param name="path">资源加载路径</param>
    /// <returns></returns>
    public GameObject GetObj(string name, string path)
    {
        //先申明一个对象
        GameObject obj = null;
        //如果字典中有该类型的对象池(柜子中有这个对象的抽屉) 且 对象池中有库存
        if (poolDic.ContainsKey(name) && poolDic[name].poolList.Count > 0)
        {
            //从抽屉中得到对象
            obj = poolDic[name].GetObj();
        }
        else
        {
            //加载并创建
            obj = Instantiate(Resources.Load<GameObject>(path));
            //将对象名和对象池名一致 
            obj.name = name;
        }
        return obj;
    }

    /// <summary>
    /// 放回对象池或新建对象池
    /// </summary>
    /// <param name="name">对象池的名字</param>
    /// <param name="obj">当前对象</param>
    public void PushObj(string name, GameObject obj)
    {
        //第一次会新建一个柜子父物体
        //所有对象池的父物体
        if (poolObj == null)
            poolObj = new GameObject("Pool");

        //如果有抽屉
        if (poolDic.ContainsKey(name))
        {
            poolDic[name].PushObj(obj);
        }
        //没有就在柜子里添加一个抽屉
        //在字典中新建一个该类型的对象池
        else
        {
            poolDic.Add(name, new PoolData(obj, poolObj));
        }
    }

    /// <summary>
    /// 转场景的时候清空对象池 在转场景后 新场景没有对象 但对象池中可能还包含对上个场景对象的引用
    /// </summary>
    public void Clear()
    {
        poolDic.Clear();
        poolObj = null;
    }

在创建的对象中挂载这个脚本即可

public class DelyPush : MonoBehaviour
{
    void OnEnable()
    {
        //延迟1秒 将对象放回对象池/新建对象池进行存放
        Invoke("Push", 1);
    }
    void Push()
    {
        Pool.Instance.PushObj(gameObject.name, gameObject);
    }
}

猜你喜欢

转载自blog.csdn.net/m0_69778537/article/details/132220474