1. 程式人生 > >Unity中的物件池

Unity中的物件池

什麼是物件池?

為了方便物件的產生和回收,我們使用一個集合來儲存不使用物件,當需要使用該物件時,從集合中取出來,不用時不進行銷燬,而是將其取消啟用,重新存入物件池中。

為什麼要使用物件池?

當一個遊戲需要頻繁的建立和銷燬物件時,為了不增加GC的效能消耗,可以考慮使用回收物件來達到複用的目的。(適用於頻繁建立和銷燬的物件)

物件池的實現

Pool(物件池):對儲存物件的集合進行了適當的封裝,用於單個遊戲物件(預製體)的回收和複用。

程式碼:

public class Pool{

    public string name = "";

    public GameObject prefab;

    Queue<GameObject> poolQueue = new Queue<GameObject>(); //使用佇列儲存物件池中的資料

    //立即回收
    public void Recycle(GameObject go)
    {
        go.GetComponent<IReset>().Reset();

        go.SetActive(false);
        poolQueue.Enqueue(go);
    }

    //延遲迴收
    public IEnumerator AutoRecycle(GameObject go, float delay)
    {
        //使用寫成,延時回收
        yield return new WaitForSeconds(delay);

        Recycle(go);
    }

    //建立物件
    public GameObject Create()
    {
        GameObject go = null;
        if (poolQueue.Count > 0)
        {
            //物件池中有需要建立的物件,從物件池中取
            go = poolQueue.Dequeue();
            go.SetActive(true);
        }
        else
        {
            //當物件池中沒有需要建立的物件時,建立物件
            go = GameObject.Instantiate(prefab);
        }
        return go;
    }
}

PoolMgr(物件池管理器):對物件池進行了進一步的封裝,可以用於建立多個物件(預製體)的回收和服用,可以更加方便的使用物件池。(物件池模組化)。

程式碼:

public class PoolMgr : MonoBehaviour {

    public Pool[] pools;

    //物件池管理器使用單例
    private static PoolMgr _instance;
    public static PoolMgr Instance {

        get {
            return _instance;
        }
    }

    void Awake() {
        if (_instance == null)
        {
            _instance = this;
        }
        else
        {
            Destroy(this.gameObject);
        }
    }

    //將物件池註冊進字典
    Dictionary<string, Pool> poolDir = new Dictionary<string, Pool>();
	void Start () {
        foreach (var item in pools)
        {
            poolDir.Add(item.name.ToLower(), item);
        }
	}

    public GameObject CreateObj(string poolName)
    {
        Pool pool;
        //TryGetValue獲取與鍵相關聯的值
        if (poolDir.TryGetValue(poolName.ToLower(),out pool))
        {
            return pool.Create();
        }

        Debug.LogError(poolName + "不存在");
        return null;
    }

    /// <summary>
    /// 立即回收
    /// </summary>

    public void RecycleObjs(string poolName, GameObject go)
    {
        Pool pool;
        if (poolDir.TryGetValue(poolName.ToLower(),out pool))
        {
            pool.Recycle(go);
        }
    }
    /// <summary>
    /// 延遲銷燬
    /// </summary>
    /// <param name="poolName">物件池名字</param>
    /// <param name="go">需要回收的物件</param>
    /// <param name="delay">延遲時間</param>
    public void RecycleObjs(string poolName, GameObject go, float delay)
    {
        StartCoroutine(DelayRecycle(poolName, go, delay));
    }

    IEnumerator DelayRecycle(string poolName, GameObject go, float delay)
    {
        //延遲呼叫的立即回收
        yield return new WaitForSeconds(delay);

        Pool pool;
        if (poolDir.TryGetValue(poolName.ToLower(),out pool))
        {
            pool.Recycle(go);
        }
    }

}

注:物件池是一種用記憶體換運存的優化技術,只有大量頻繁建立和銷燬的物件使用物件池,才能起到優化作用,否則不具有優化效果。