對象池技術(shù)

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)行不斷的初始化和銷毀。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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