《Unity3D》通過對象池模式,管理情境中的元素

來源:互聯網
上載者:User

標籤:style   class   blog   code   tar   color   

池管理類有啥用?

在遊戲情境中,我們有時候會需要複用一些遊戲物體,比如常見的子彈、子彈碰撞類,某些情況下,怪物也可以使用池管理,UI部分比如:血條、文字等等

這些元素共同的特性是:存在固定生命週期,使用比較頻繁,情境中大量使用。

所以,我們就通過池管理思路,在遊戲初始化的時候,產生一個初始的池,存放我們要複用的元素,

當要用到時,從池中取出;生命週期結束,放回到池中。

代碼

這個池的參數有兩個:1池中存放的元素 2 池的初始容量(如果池不夠了,則會按照這個容量進行擴充)

代碼如下

using System.Collections;using System.Collections.Generic;using UnityEngine;/// <summary>/// 通用的池管理類/// </summary>public class ObjectPoolManager : MonoBehaviour{    #region 公用屬性    /// <summary>    /// 池中所使用的元素Prefab    /// </summary>    public GameObject ObjPrefab;    /// <summary>    /// 初始容量    /// </summary>    public int InitialCapacity;    #endregion    #region 私人屬性    /// <summary>    /// 初始下標    /// </summary>    private int _startCapacityIndex;    /// <summary>    /// 可用下標    /// </summary>    private List<int> _avaliableIndex;    /// <summary>    /// 池中全部元素    /// </summary>    private Dictionary<int, GameObject> _totalObjList;    #endregion    #region 事件/重寫方法    void Start()    {        _avaliableIndex = new List<int>(InitialCapacity);        _totalObjList = new Dictionary<int, GameObject>(InitialCapacity);        expandPool();    }    #endregion    #region 公用方法    /// <summary>    /// 取得一個物體,傳回值 1,obj代表,ID是1的物體被取到,ID可以用來歸還物體的時候用到    /// </summary>    /// <returns></returns>    public KeyValuePair<int, GameObject> PickObj()    {        if (_avaliableIndex.Count == 0)            expandPool();        int id = _avaliableIndex[0];        _avaliableIndex.Remove(id);        _totalObjList[id].SetActive(true);        return new KeyValuePair<int, GameObject>(id, _totalObjList[id]);    }    /// <summary>    /// 從池中取出元素,在制定時間後回收    /// </summary>    /// <param name="existSecond"></param>    /// <returns></returns>    public KeyValuePair<int, GameObject> PickObjWithDelayRecyle(float existSecond)    {        KeyValuePair<int, GameObject> obj = PickObj();        StartCoroutine(startRecycleExplosion(obj.Key, existSecond));        return obj;    }    /// <summary>    /// 回收一個物體    /// </summary>    /// <param name="id"></param>    public void RecyleObj(int id)    {        _totalObjList[id].SetActive(false);        _totalObjList[id].transform.parent = transform;        _avaliableIndex.Add(id);    }    #endregion    #region 私人方法    IEnumerator startRecycleExplosion(int id, float waitTime)    {        yield return new WaitForSeconds(waitTime);        RecyleObj(id);    }    /// <summary>    /// 擴充池    /// </summary>    private void expandPool()    {        int start = _startCapacityIndex;        int end = _startCapacityIndex + InitialCapacity;        for (int i = start; i < end; i++)        {            //加入驗證判斷,避免在多個請求同時觸發擴充池需求            if (_totalObjList.ContainsKey(i))                continue;            GameObject newObj = Instantiate(ObjPrefab) as GameObject;            newObj.SetActive(false);            _avaliableIndex.Add(i);            _totalObjList.Add(i, newObj);        }        _startCapacityIndex = end;    }    #endregion}

 

值得注意的是:放回池中的時候,我們把元素的父節點也設定為池元素,這樣做是避免當元素掛載的對象在記憶體中被刪除的時候,元素也被刪除的問題。

調用

 將本類掛載到情境中的某個GameObject上,在U3D編輯介面進行參數的賦值,就可以再遊戲中訪問了。

聲明方式:
 ObjectPoolManager _bulletPool = GameObject.Find("你掛載的物體名稱").GetComponent<ObjectPoolManager>();
取出元素:
  KeyValuePair<int, GameObject> bulletKV = _bulletPool.PickObj();
放回:
 _bulletPool.RecyleObj(bulletID);

 

在本人的實際使用中,用這個類管理了

  1. 子彈
  2. 子彈碰撞特效
  3. 攻擊特效
  4. 被攻擊特效
  5. 怪物血條(基於NGUI製作)
  6. 情境部分文字(施法時、怪物被攻擊時,基於NGUI製作)
  7. 等等。。

歡迎各位進行討論

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.