小白學(xué)U3D對(duì)象池

對(duì)于unity之中的對(duì)象池技術(shù)葱跋,想必大家都有多耳聞,但是覺(jué)得沒(méi)有多大的必要去使用崔步,我剛開始學(xué)unity時(shí)候也是這么想的稳吮,但是后來(lái)我才意識(shí)到,隨著你所做的項(xiàng)目的規(guī)模的擴(kuò)大井濒,你可能需要頻繁的對(duì)某的游戲?qū)ο螅℅ameObject)進(jìn)行實(shí)例化灶似,在銷毀。假設(shè)你在開發(fā)一個(gè)FPS游戲瑞你,玩家酪惭,乃至大量的AI機(jī)器人都需要頻繁的通過(guò)實(shí)例化“子彈”然后在子彈發(fā)生碰撞后銷毀。
下面是我寫的實(shí)例化小兵(協(xié)程)以及銷毀小兵程序(無(wú)對(duì)象池)

IEnumerator Test01(int number)
    {
        numNO = 0;
        while (numNO < number)
        {
            numNO++;
            //每個(gè)怪產(chǎn)生的時(shí)間差
            if (boNO > 5)
                yield return new WaitForSeconds(numwait / 2);
            else
                yield return new WaitForSeconds(numwait);
            string a = ChooseEnemy(boNO,numNO);
            //動(dòng)態(tài)實(shí)例化者甲,Load(“路徑自定春感,但必須在Resources文件夾里”)
            GameObject enemy = (GameObject)Resources.Load("Prefabs_Enemy/"+a);
            enemy.GetComponent<EnemyContrl>().Pos = GameObject.FindGameObjectWithTag("WayPos");
            //print(enemy.GetComponent<EnemyContrl>().Pos.name);
            GameObject o;
            //如果在飛行怪,則拔高5
            if (enemy.tag == "FlyEnemy")
            {
                o = Instantiate(enemy, transform.position + Vector3.up * 5, transform.rotation);
            }
            else
                o =  Instantiate(enemy,transform.position,transform.rotation);
            o.transform.parent = transform;

        }

    }
    /// <summary>
    /// 選擇怪物種類,儲(chǔ)存動(dòng)態(tài)實(shí)例化需要的文件名
    /// </summary>
    /// <param name="boNO"></param>波次
    /// <param name="numNO"></param>怪次
    /// <returns></returns>
    string ChooseEnemy(int boNO, int numNO)
    {

        switch(boNO % 3)
        {

            case 1:
                {
                    if (numNO < 8)
                    {
                        str = "AmurTiger_01";
                    }
                    else if (numNO < 10 && numNO >= 8)
                    {
                        str = "AmurTiger_02";
                    }
                    else
                    {
                        str = "AmurTiger_03";
                    }
                    break;
                }
            case 2:
                {
                    if (numNO < 8)
                    {
                        str = "GiantBat";
                    }
                    else if (numNO < 10 && numNO >= 8)
                    {
                        str = "GiantBat_2";
                    }
                    else
                    {
                        str = "GiantBat_3";
                    }
                    break;
                }
            case 3:
                {
                    if (numNO < 8)
                    {
                        print("3-1");
                        str = "Manticore_01";
                    }
                    else if (numNO < 10 && numNO >= 8)
                    {
                        print("3-2");
                        str = "Manticore_02";
                    }
                    else
                    {
                        str = "Manticore_03";
                    }
                    break;
                }
            case 0:
                {
                    if (numNO < 4)
                    {
                        str = "GiantBat_2";
                    }
                    else if (numNO < 7 && numNO >= 4)
                    {
                        str = "AmurTiger_02";
                    }
                    else if (numNO <= 10 && numNO >= 7)
                    {
                        str = "Manticore_02";
                    }
                    break;
                }
        }
        return str;
    }
public void EnemyDead(float Blood)
    {
        if (Blood <= 0)
        {
            this.gameObject.GetComponent<Collider>().enabled = false;
            Destroy(this.gameObject.GetComponent<Rigidbody>());
            //殺怪物獲得金幣
            GameData.Instance.money += 10;
            Ani.SetBool("Dead", true);
            Ani.SetBool("Attack", false);
            //agt.SetDestination(this.transform.position);
            this.gameObject.GetComponent<NavMeshAgent>().enabled = false;
            Timer += Time.deltaTime;
            if (Timer >= DestryTime) 
            {
                Destroy(this.gameObject);
            }
        }
    }

當(dāng)然也有可能是使用觸發(fā)器形式等等就不一一舉例子了鲫懒。這么操作雖然方便快捷纺铭,信手拈來(lái)但是這樣做會(huì)占用很多內(nèi)存資源,如果頻繁這樣操作可能會(huì)導(dǎo)致游戲卡頓甚至閃退刀疙。
那么對(duì)象池技術(shù)就在這種情況下被引入了進(jìn)來(lái)舶赔,所謂的對(duì)象池技術(shù)就是我們把用到的對(duì)象在初始化的時(shí)候都放到這個(gè)對(duì)象池中,需要用到時(shí)可以從激活拿來(lái)用谦秧,不需要用時(shí)可以繼續(xù)禁用放回對(duì)象池中竟纳,這樣大大減少因?yàn)榇罅康膶?shí)例化和銷毀帶來(lái)的性能消耗。

1.新建Unity項(xiàng)目疚鲤,首先創(chuàng)建ObjectPoolsManager.cs管理類锥累,利用單例模式封裝對(duì)象池技術(shù)所用的方法,主要是為了方便調(diào)用集歇;代碼如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
/// <summary>
/// 對(duì)象池控制管理腳本
/// </summary>
public class ObjectPoolsManager 
{
        /// <summary>
        /// 1.對(duì)象池-列表存儲(chǔ)單個(gè)對(duì)象
        /// </summary>
        List<GameObject> _poolList;
 
        /// <summary>
        /// 2.對(duì)象池-字典存儲(chǔ)對(duì)象
        /// </summary>
        Dictionary<int,List<GameObject>> _poolDictionary;
 
        private static ObjectPoolsManager _singleton;
 
        public static ObjectPoolsManager GetInstance()
        {
                if (_singleton == null) {
                 
                        _singleton = new ObjectPoolsManager ();
                }
                return _singleton;
        }
 
        public ObjectPoolsManager()
        {
                _poolList=new List<GameObject> ();
                _poolDictionary =new Dictionary<int, List<GameObject>>();
 
        }
 
        /// <summary>
        /// 實(shí)例化并存儲(chǔ)游戲?qū)ο蟪刂校▎蝹€(gè)對(duì)象)
        /// </summary>
        /// <param name="gameObject">被創(chuàng)建的游戲?qū)ο?lt;/param>
        /// <param name="pos">游戲?qū)ο笪恢?lt;/param>
        /// <param name="rotation">游戲?qū)ο笮D(zhuǎn)</param>
        public GameObject SetActiveObject(GameObject gameObject,Vector3 pos,Quaternion rotation)
        {
                 
                if (_poolList.Count>0) {
 
                        GameObject result = _poolList [0];
                        _poolList.Remove (result);
                        result.SetActive (true);
                        result.transform.position = pos;
                        result.transform.rotation = rotation;
                        return result;
                }
                return  GameObject.Instantiate (gameObject,pos,rotation) as GameObject;;
        }
 
 
        /// <summary>
        /// 實(shí)例化并存儲(chǔ)游戲?qū)ο蟪刂校ǘ鄠€(gè)對(duì)象)
        /// </summary>
        /// <param name="gameObject">被創(chuàng)建的游戲?qū)ο?lt;/param>
        /// <param name="pos">游戲?qū)ο笪恢?lt;/param>
        /// <param name="rotation">游戲?qū)ο笮D(zhuǎn)</param>
        public GameObject SetActiveMutilObject(GameObject gameObject,Vector3 pos,Quaternion rotation)
        {
                int key = gameObject.GetInstanceID ();
                if (_poolDictionary.ContainsKey (key)) {
                 
                        if (_poolDictionary [key].Count > 0) {
 
                                GameObject result = _poolDictionary [key] [0];
                                result.SetActive (true);
                                _poolDictionary [key].Remove (result);
                                result.transform.position = pos;
                                result.transform.rotation = rotation;
                                return result;
                        }
 
                }
                GameObject curObj = GameObject.Instantiate (gameObject,pos,rotation) as GameObject;
                curObj.name = gameObject.GetInstanceID ().ToString();
 
                return curObj;
        }
 
        /// <summary>
        /// 隱藏當(dāng)前對(duì)象桶略,并且添加到列表
        /// </summary>
        /// <param name="gameObject">被創(chuàng)建的游戲?qū)ο?lt;/param>
        public void SetDisableObject(GameObject gameObject)
        {
                gameObject.SetActive (false);
                _poolList.Add (gameObject);
        }
 
 
        /// <summary>
        /// 隱藏當(dāng)前對(duì)象,并且添加到字典中
        /// </summary>
        /// <param name="gameObject">被創(chuàng)建的游戲?qū)ο?lt;/param>
        public void SetDisableMutilObject(GameObject gameObject)
        {
                gameObject.SetActive (false);
                int key = int.Parse (gameObject.name);
                //不包含鍵名則添加進(jìn)字典一條新的儲(chǔ)存單個(gè)對(duì)象的List
                if (!_poolDictionary.ContainsKey (key)) {
                        _poolDictionary.Add (key,new List<GameObject>());
                }
                //將gameObject添加進(jìn)他所在的List
                _poolDictionary[key].Add(gameObject);
        }
 
        /// <summary>
        /// 延遲隱藏游戲?qū)ο蠡逵睿⑻砑拥搅斜碇?        /// </summary>
        /// <returns>The disable object.</returns>
        /// <param name="gameObject">被創(chuàng)建的游戲?qū)ο?lt;/param>
        /// <param name="time">延遲時(shí)間</param>
        public IEnumerator IEDisableObject(GameObject gameObject,float time)
        {
                //協(xié)程:延遲time秒
                yield return new WaitForSeconds (time);
                GetInstance ().SetDisableObject (gameObject);
        }
 
        /// <summary>
        /// 延遲隱藏游戲?qū)ο蠹始撸⑻砑拥阶值渲?        /// </summary>
        /// <returns>The disable object.</returns>
        /// <param name="gameObject">被創(chuàng)建的游戲?qū)ο?</param>
        /// <param name="time">延遲時(shí)間</param>
        public IEnumerator IEDisableMutilObject(GameObject gameObject,float time)
        {
                //協(xié)程:延遲time秒
                yield return new WaitForSeconds (time);
                GetInstance ().SetDisableMutilObject (gameObject);
        }
 
}

其中:

字典允許值對(duì)象為null,并且沒(méi)有個(gè)數(shù)限制姑蓝,所以當(dāng)get()方法的返回值為null時(shí)鹅心,可能有兩種情況,一種是在集合中沒(méi)有該鍵對(duì)象纺荧,另一種是該鍵對(duì)象沒(méi)有映射任何值對(duì)象旭愧,即值對(duì)象為null。因此宙暇,在_poolDictionary字典中不應(yīng)該利用get()方法來(lái)判斷是否存在某個(gè)鍵输枯,而應(yīng)該利用containsKey()方法來(lái)判斷

2.接著簡(jiǎn)單創(chuàng)建一個(gè)測(cè)試對(duì)象池類TestObjectPoolsBehaviour.cs,組件直接掛載到場(chǎng)景中即可占贫;

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
/// <summary>
/// 測(cè)試對(duì)象池腳本
/// </summary>
public class TestObjectPoolsBehaviour : MonoBehaviour {
 
        public GameObject TestObj;
        public GameObject[] TestObjSet;
        public float DelayTime = 3;
 
 
        void Update ()
        {
                if (Input.GetKeyDown(KeyCode.A)) {
                        //單個(gè)游戲?qū)ο?                        GameObject obj = ObjectPoolsManager.GetInstance ().SetActiveObject (TestObj,Vector3.zero,TestObj.transform.rotation) as GameObject;
                        StartCoroutine (ObjectPoolsManager.GetInstance().IEDisableObject(obj,DelayTime));
                }
 
                if (Input.GetKeyDown(KeyCode.B)) {
                        //多個(gè)游戲?qū)ο?                        //實(shí)例化
                        GameObject obj = ObjectPoolsManager.GetInstance ().SetActiveMutilObject (TestObjSet[0],Vector3.zero,TestObjSet[0].transform.rotation) as GameObject;
                        //延遲隱藏
                        StartCoroutine(ObjectPoolsManager.GetInstance().IEDisableMutilObject(obj,DelayTime));
                }
 
                if (Input.GetKeyDown(KeyCode.C)) {
                        //多個(gè)游戲?qū)ο?                        //實(shí)例化
                        GameObject obj = ObjectPoolsManager.GetInstance ().SetActiveMutilObject (TestObjSet[1],Vector3.zero,TestObjSet[1].transform.rotation) as GameObject;
                        //延遲隱藏
                        StartCoroutine(ObjectPoolsManager.GetInstance().IEDisableMutilObject(obj,DelayTime));
                }
                 
        }
}

這樣的話桃熄,在我們大量,頻繁使用某游戲?qū)ο髸r(shí)靶剑,就可以不必消耗大量?jī)?nèi)存來(lái)頻繁的實(shí)例化再銷毀蜻拨,完全可以,用對(duì)象池桩引,使用SetActive的true,false來(lái)“實(shí)現(xiàn)實(shí)例化與銷毀”缎讼。
不單再FPS游戲中,在塔防游戲里坑匠,也會(huì)用到對(duì)象池技術(shù)血崭。下面是我做的一個(gè)塔防游戲Demo,雖然看起來(lái)很low,但是重點(diǎn)是學(xué)習(xí)不是嗎夹纫。

小白開心的拍起了肚皮1.jpg
小白開心的拍起了肚皮2.jpg
小白開心的拍起了肚皮3.jpg
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末咽瓷,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子舰讹,更是在濱河造成了極大的恐慌茅姜,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,204評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件月匣,死亡現(xiàn)場(chǎng)離奇詭異钻洒,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)锄开,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門素标,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人萍悴,你說(shuō)我怎么就攤上這事头遭。” “怎么了癣诱?”我有些...
    開封第一講書人閱讀 164,548評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵计维,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我狡刘,道長(zhǎng)享潜,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,657評(píng)論 1 293
  • 正文 為了忘掉前任嗅蔬,我火速辦了婚禮,結(jié)果婚禮上疾就,老公的妹妹穿的比我還像新娘澜术。我一直安慰自己,他們只是感情好猬腰,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評(píng)論 6 392
  • 文/花漫 我一把揭開白布鸟废。 她就那樣靜靜地躺著,像睡著了一般姑荷。 火紅的嫁衣襯著肌膚如雪盒延。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,554評(píng)論 1 305
  • 那天鼠冕,我揣著相機(jī)與錄音添寺,去河邊找鬼。 笑死懈费,一個(gè)胖子當(dāng)著我的面吹牛计露,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,302評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼票罐,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼叉趣!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起该押,我...
    開封第一講書人閱讀 39,216評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤疗杉,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后蚕礼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體烟具,經(jīng)...
    沈念sama閱讀 45,661評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評(píng)論 3 336
  • 正文 我和宋清朗相戀三年闻牡,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了净赴。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,977評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡罩润,死狀恐怖玖翅,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情割以,我是刑警寧澤金度,帶...
    沈念sama閱讀 35,697評(píng)論 5 347
  • 正文 年R本政府宣布,位于F島的核電站严沥,受9級(jí)特大地震影響猜极,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜消玄,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評(píng)論 3 330
  • 文/蒙蒙 一跟伏、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧翩瓜,春花似錦受扳、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至坟桅,卻和暖如春华望,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背仅乓。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工赖舟, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人方灾。 一個(gè)月前我還...
    沈念sama閱讀 48,138評(píng)論 3 370
  • 正文 我出身青樓建蹄,卻偏偏與公主長(zhǎng)得像碌更,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子洞慎,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • This article is a record of my journey to learn Game Deve...
    蔡子聰閱讀 3,781評(píng)論 0 9
  • 這個(gè)是我剛剛整理出的Unity面試題痛单,為了幫助大家面試,同時(shí)幫助大家更好地復(fù)習(xí)Unity知識(shí)點(diǎn)劲腿,如果大家發(fā)現(xiàn)有什么...
    編程小火雞閱讀 3,896評(píng)論 2 35
  • Unity3D 里有兩種動(dòng)態(tài)加載機(jī)制:一個(gè)是Resources.Load旭绒,另外一個(gè)通過(guò)AssetBundle,其實(shí)...
    IongX閱讀 1,725評(píng)論 0 5
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,133評(píng)論 25 707
  • 上次的分享會(huì)我們分享了很多機(jī)械鍵盤的東西,現(xiàn)場(chǎng)體驗(yàn)青軸焦人、紅軸挥吵、靜電容鍵盤的手感。來(lái)自杭州的朋友還介紹了他的一種關(guān)于...
    劍山閱讀 761評(píng)論 0 50