Unity中对象池技术的应用

89 阅读2分钟

1.对象池概述

对象池是存放对象的缓冲区。用户可以从缓冲区中放入/取出对象。一类对象池存放一类特定的对象。那么对象池有什么用呢?在游戏中,经常会有产生/销毁大量同类游戏对象的需求,比如游戏中源源不断的敌人、频繁刷新的宝箱、乃至一些游戏特效(风、雨等)。如果没有一种比较好的机制来管理这些对象的产生和销毁,而是Instantiate和Destroy,将使你的游戏性能大大下降,甚至出现卡死、崩溃……

2.对象池实现

  简而言之,就是当需要使用一个对象的时候,直接从该类对象的对象池中取出(SetActive(true)),如果对象池中无可用对象,再进行Instantitate。而当不再需要该对象时,不直接进行Destroy,而是SetActive(false)并将其回收到对象池中。下面直接贴下代码:

2.1实现对象池ObjectPool

public class ObjectPool : MonoBehaviour
{
    //池中对象

    private PooledObject prefab;

    //存储可用对象的缓冲池
    private List<PooledObject> objectedPools = new List<PooledObject>();

    //从池中取出对象,返回该对象
    public PooledObject GetObject()
    {
        PooledObject obj;
        int objectedPoolsIndex=objectedPools.Count-1;
        if (objectedPoolsIndex >= 0)
        {
            obj = objectedPools[objectedPoolsIndex];
            objectedPools.RemoveAt(objectedPoolsIndex);
            obj.gameObject.SetActive(true);
        }

        else  //池中无可用obj
        {
            obj = Instantiate<PooledObject>(prefab);
            obj.transform.SetParent(transform, false);
            obj.pool = this;
        }

        return obj;
    }

    //向池中放入对象
    public void AddObject(PooledObject obj)
    { 
        obj.gameObject.SetActive(false);
        objectedPools.Add(obj);
    }

    //静态方法,创建并返回对象所属的对象池
    public static ObjectPool GetPool(PooledObject prefab)
    {
        GameObject obj;
        ObjectPool pool;
        //编辑器模式下检查是否有同名的pool存在,放置重复创建pool
        if (Application.isEditor)
        {
            obj = GameObject.Find(prefab.name + "Pool");
            if (obj)
            {
                pool = obj.GetComponent<ObjectPool>();
                if (pool != null) 
                {
                    return pool;
                }
            }
        }
        obj = new GameObject(prefab.name + " Pool");
        DontDestroyOnLoad(obj);
        pool = obj.AddComponent<ObjectPool>();
        pool.prefab = prefab;
        return pool;
    }
}

2.2 运用对象池

/// <summary>
/// 所有需要使用对象池机制的对象的基类
/// </summary>
public class PooledObject : MonoBehaviour
{
    //归属的池
    public ObjectPool pool { get; set; }

    //场景中某个具体的池
    [System.NonSerialized]
    private ObjectPool poolInstanceForPrefab;

    //回收对象到对象池中
    public void ReturnToPool()
    {
        if (pool)
        {
            pool.AddObject(this);
        }
        else
        {
            Destroy(gameObject);
        }
    }

    /// <summary>
    /// 返回对象池中可用对象的实例
    /// </summary>
    public T GetPooledInstance<T>() where T : PooledObject
    {
        if (!poolInstanceForPrefab)
        {
            poolInstanceForPrefab = ObjectPool.GetPool(this);
        }
        return (T)poolInstanceForPrefab.GetObject();
    }

}