Object pooling - 基本物件池與應用

N 人看过

You can also see my post in Bahamut.

什麼是Object pooling

在我們製作一些遊戲的時候,常常需要使用到一些重複且相同的物件,

如果我們照著一般物件產生以及消除的方法:Instantiate 以及 Destroy,

會使許多GameObject(object)用完慘遭系統GC,如果像是子彈或者音樂遊戲的object被大量GC,

很可能造成遊戲卡頓,對於音樂遊戲或者是捲軸射擊遊戲都是相當致命的傷害,

為了避免這種問題,我們使用Object pool來儲存可以使用的object們,來免於上述的問題。

那麼Object pool該如何在C#中實作呢?

以下是一個Object pool 的簡單範例:

ObjectPool

可以看到,我使用Queue作為最基本的element存放結構,

在這邊稍微補充Queue的作用給沒有聽過的人:

Queue 是一個first in first out(先進先出)的資料結構,可以用來存放需要順序性的資料,例如網路

傳送的封包等,Queue有幾個基本的操作:Enqueue可以將物件存放到Queue的尾端,Dequeue

可以從Queue的開頭來拿取物件,對於我們這個object pool的實作並不是唯一的選擇,只是筆者

習慣上所做的選擇而已。

另外,在這個class中,可以看到建構子需要傳入創建object的創建方式,對於一般c#的物件來

說,通常是以new運算子開頭的建構函數,而對於unity的GameObject來說,便是Instantiate方法

了。

使用上,只需要呼叫GetObject就可以接收到object pool內儲存的物件,如果物件池中已經沒有物

件了,我們就會使用一開始指定的方法出創建新的物件來回傳。

另外,當我們使用完這個物件之後,我們可以呼叫Recycle方法,將這個物件回收起來,這樣如果

下次需要呼叫object pool裡頭的物件,我們就可以重複利用這個物件了!

如何將物件池應用於Unity中

我們目前實作的物件池,其實只能將物件這個reference記錄起來,避免它被系統給GC,但如果

要真的在Unity裡面重複使用,還必須將物件本身藏起來才行,例如下面這個子彈發射的例子:

Bullet Example

在回收子彈時,同時將它設為Inactive。

Bullet Example

如果我們從pool中拿取子彈拿來使用,就必須將它Active,否則他是無法運作的。

當然,在Unity的Object pool實作上面,除了將他Inactive拿掉以外,也可以將該GameObject移出

遊戲畫面外,如果有較為耗效能的component再利用腳本關閉,這樣會比active該GameObject

能獲得更好的效能,大家有興趣的話,也可以自己實作看看喔!

這是上面的子彈範例專案檔,大家也可以下載下來試試看:Google雲端

*本文章提及所有code以及專案中所有code都可以任意修改使用,不需進行告知!