Unity3D开发之对象池

    在做UI的下拉列表和游戏中物体的实例化时,我们经常会用到对象池。因为对象池会把生成的物体回收起来供下次使用,节省很大的性能。

    项目中通常会有多个不同类型的预制体需要被大量复制,所以我们首先要创建一个子池来产生不同类型的预制体,然后在创建一个大池子来存储管理所有被实例化的不同类型的预制体。首先来完成我们的子池脚本:

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

public class SubPool
{
    //所有实例化出来的物体管理器
    private List objects = new List();

    //废弃不用的物体管理器
    private List discardObjects = new List();

    private GameObject prefab;


    private GameObject Pool;//将不用的东西放到Pool池子里

    public string Name { get { return prefab.name; } }

    public SubPool(GameObject go, GameObject Pool)
    {
        this.prefab = go;
        this.Pool = Pool;
    }
    //取出物体
    public GameObject Spawn(Transform parent)
    {
        GameObject go = null;

        if (discardObjects.Count > 0)
        {
            go = discardObjects[0];
            discardObjects.Remove(go);
        }

        if (go == null)
        {
            go = GameObject.Instantiate(prefab);
            objects.Add(go);
        }
        go.transform.SetParent(parent);
        go.SetActive(true);
        return go;
    }

    //回收物体
    public void UnSpawn(GameObject go)
    {
        if (objects.Contains(go))
        {
            go.SetActive(false);
            discardObjects.Add(go);
            go.transform.SetParent(Pool.transform);
        }
    }
    //回收所有物体
    public void UnSpawnAll()
    {
        discardObjects.Clear();
        for (int i = 0; i < objects.Count; i++)
        {
            UnSpawn(objects[i]);
            discardObjects.Add(objects[i]);
        }
    }

    public bool Contain(GameObject go)
    {
        return objects.Contains(go);
    }
}

    然后在创建一个大池子来管理这些被实例化的物体:

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

public class ObjectPool : MonoBehaviour
{
    public static ObjectPool Instance = null;

    private GameObject Pool;

    void Awake()
    {
        Instance = this; Pool = new GameObject("Pools");
    }


    /// 
    /// 资源目录
    /// 
    public string ResourceDir = "Pool";

    Dictionary pools = new Dictionary();

    //取出物体
    public GameObject Spawn(string name, Transform trans)
    {
        SubPool subPool = null;
        if (!pools.ContainsKey(name))
            CreatNewsubPool(name, trans);

        subPool = pools[name];
        return subPool.Spawn(trans);
    }
    //回收物体
    public void UnSpawn(GameObject go)
    {
        SubPool pool = null;
        foreach (var p in pools.Values)
        {
            if (p.Contain(go))
            {
                pool = p;
                break;
            }
        }
        pool.UnSpawn(go);
    }

    // 回收所有物体
    public void UnSpawnAll()
    {
        foreach (var p in pools.Values)
        {
            p.UnSpawnAll();
        }
    }

    //回收预制体名字为name的物体
    public void UnspawnAll(string name)
    {
        if (pools.ContainsKey(name))
        {
            pools[name].UnSpawnAll();
        }
    }

    //新建一个池子
    private void CreatNewsubPool(string name, Transform parent)
    {
        string path = ResourceDir + "/" + name;

        GameObject go = (Resources.Load(path));

        SubPool pool = new SubPool(go, Pool);
        pools.Add(name, pool);
    }
}

ObjectPool是单利模式,我们获取的时候直接全局获取来控制。在使用对象池取物体时,我们调用Spawn函数并传入预制体的名字以及对象池里的物体要放到的父物体下,通常我们在调用之前一般会将之前的隐藏,比如刷新列表重新载入数据。代码如下:

//先全部回收
        for (int i = 0; i().Init(i, roomDatas[i],this);
        }

    以上是我在项目中遇到的对象池使用问题。

    如果本博客对你有帮助,记得点关注哦!

 

2019.7.3更:

其实最初的模板是照着siki学院的一个老师讲的模板写的,后来在项目应用中发现局限性越来越大以及功能性越来越小。所以就在不断的迭代更改。

新增的:

1.可以回收指定名字的对象池内所有物体。

2.Gameobject也可以隐藏但不被回收。

你可能感兴趣的:(Unity)