Unity 對象池技術(shù)
為什么使用對象池?
在我們開發(fā)中,往往會遇見需要不斷創(chuàng)建和銷毀同一物體的情況。(如飛機(jī)大戰(zhàn),許多FPS游戲,三消類游戲等),這時我們系統(tǒng)不斷的實(shí)例化資源和銷毀資源對于內(nèi)存以及性能的消耗是非常大的。對于這種我們可以使用對象池技術(shù)進(jìn)行優(yōu)化。效果十分明顯。
對象池及時的原理:
適用范圍:有大量的物體需要被不斷的創(chuàng)建和銷毀的時候。
關(guān)鍵點(diǎn):
從對象池中放入對象。
從對象池中取出對象。
使用何種數(shù)據(jù)類型來對這些對象進(jìn)行儲存。
關(guān)鍵思想:
相比于Instantiate和Destroy,不斷的實(shí)例化和銷毀,對象池只是對它們實(shí)例化出的對象進(jìn)行激活和失活的處理。
我們配合Unity來進(jìn)行實(shí)際的演示。
以最簡單的打磚塊案例進(jìn)行講解,具體自己的項(xiàng)目自己進(jìn)行分析和解決。
首先通過腳本動態(tài)創(chuàng)建出一堵墻。
Paste_Image.png
通過射線實(shí)現(xiàn)子彈的發(fā)射。點(diǎn)擊時創(chuàng)建預(yù)設(shè)并拿到預(yù)設(shè)的剛體組件添加力。
如果我們不進(jìn)行銷毀,那子彈將會一直存在于我們的場景,對我們的內(nèi)存造成巨大的負(fù)擔(dān),這里我們可以是Destroy方法進(jìn)行延時銷毀。
但問題又來了這只是一個小小的Demo,如果我們的游戲場景里的資源有許多許多加上特效加上各種開銷,我們?nèi)绻龠@樣不斷的向內(nèi)存申請空間創(chuàng)建對象在銷毀對象,這樣使性能十分的低效。
通過上述例子我們可以發(fā)現(xiàn),子彈是不斷的被創(chuàng)建又不斷的被銷毀。符合我們的對象池技術(shù)需求。
使用對象池。
首先在場景中的游戲控制器上添加ObjectPool腳本。
ObjectPool的核心思想為如果存入對象池中,如何取出,用什么數(shù)據(jù)類型存儲
我們來對ObjectPool類進(jìn)行實(shí)現(xiàn)
如何存儲
由于對象池是管理整個游戲的,并且我們的對象池只需要一個,我們需要單例模式。
我們的對象池中可能不僅僅只有Bullet子彈這一種需要管理的資源,還有許多可能需要儲存的資源,我們需要使用一個數(shù)組來進(jìn)行存儲,但是每種資源的類型都是不同的,所以這里我們可以使用ArrayList這種數(shù)據(jù)類型來進(jìn)行存儲。
我們的每一種資源則對應(yīng)了儲存這種資源的ArrayList,所以我們可以使用鍵值對來進(jìn)行一一對應(yīng)。
思路邏輯清晰以后,我們來開始進(jìn)行實(shí)現(xiàn)。
構(gòu)建ObjectPool類。使用單例模式并添加鍵值對來進(jìn)行儲存。(這里為了簡單方便講解使用string類型作為key)
Paste_Image.png
接著我們需要對資源進(jìn)行儲存。(將數(shù)據(jù)存入對象池)
這里構(gòu)建一個Return方法來實(shí)現(xiàn)儲存。
首先跟著游戲?qū)ο蟮拿肿鳛閗ey
如果pool鍵值對中有key的值,我們將它Add在key所對應(yīng)的ArrayList中。
如果pool鍵值對中沒有key的值,我們則為這個key開辟一個ArrayList用于存儲它。
并將它的Active設(shè)置為false(場景中的表現(xiàn)為消失,效果同Destroy但是這個資源并沒有被回收)
Paste_Image.png
我們定義一個Get方法用于往對象池里取出對象。
Get類的設(shè)計(jì)思路,由于我們實(shí)例化出來的預(yù)設(shè)都是作為(Clone)來存在,所以我們將鍵值對的Key定義為一個原預(yù)設(shè)名加上(Clone)的形式。
聲明一個Object的對象o。
判斷鍵值對中是否有這個鍵,如果有,再判斷這個鍵所對應(yīng)的值是否為空。如果不為空,則將這個對象從ArrayList中取出后并在Arrarlist中刪除。
作為我們需要使用的對象,由于之前儲存的時候,我們將對象失活,現(xiàn)在我們需要將它激活,并設(shè)置它相應(yīng)的position,和rotation。
如果不是上述的情況,說明我們的對象現(xiàn)在還沒有被實(shí)例化出來(或者是需要從對象池中取出的數(shù)量小于場景中需要使用的數(shù)量時),我們就需要實(shí)例化對象。這里使用Resources.Load方法。
Paste_Image.png
Paste_Image.png
對象池構(gòu)建完畢以后,我們將對象池進(jìn)行應(yīng)用。
直接使用對象池的對象來獲取對象,而不是直接實(shí)例化出來對象。
Paste_Image.png
在Destroy方法處,進(jìn)行相應(yīng)的修改。
首先我們要淘汰之前的Destroy方法。
Paste_Image.png
并聲明一個初始化的方法,用于開啟協(xié)程。(每隔兩秒將實(shí)例化出來的對象失活并儲存入對象池中)
接著我們就不能再Srart中去調(diào)用這個方法,因?yàn)镾tart只能在對象實(shí)例化之后運(yùn)行一次,而我們進(jìn)行的是不斷的失活和激活的動作。對象從對象池中使用是,不斷的失活和激活過程(拿出來使用是激活,使用過后放回去失活),所以我們需要把這個失活的操作放在OnEnable()回調(diào)方法中,讓它延時2f進(jìn)行失活而不能放在Start中。
對象池完成。
這樣對象池就會根據(jù)我們子彈的生命周期(這里是2f),初始化和復(fù)用相應(yīng)數(shù)量的游戲?qū)ο螅褂脮r就激活,不使用時就失活。不會再進(jìn)行不斷的初始化和銷毀。