遊戲隨筆之遊戲資源池的設計

2022-07-04 18:18:13 字數 4120 閱讀 4902

一、遊戲專案中的資源池

在一款遊戲中,隨著遊戲的進行,我們會不斷的建立和銷毀一些角色,比如我們玩一款射擊遊戲,我們需要不斷的發射子彈,一般的情況下,我們會不斷的建立子彈,然後發射出去,在擊中物體後銷毀。分析整個設計的過程,我們會不斷的建立子彈,然後發射出去,最後銷毀它。這兒,其實就可以引入資源池的概念來解決子彈的反覆建立和銷毀。

如果只是反覆的建立和銷毀子彈,那麼每次的效能點主要在子彈的建立上,在場景中有較多角色頻繁操作射擊的時候,不斷執行建立,會帶來效能的較大消耗,從而讓遊戲卡幀。如果我們把這些子彈預先建立出來,塞入到乙個彈夾,然後每次在射擊發射子彈的時候,從預先建立的彈夾中取出來發射,每次在銷毀的時候,又將其還原到彈夾中,這樣迴圈反覆的利用,可以避免每次射擊子彈的時候的建立操作帶來的效能消耗。將彈夾拓展一步,就是資源池的概念了。

二、不同設計下的資源池

1、簡單lua版本的資源池

基於前文子彈的闡述,我就寫乙個簡單版本的資源池的lua版本,首先,是資源池的定義:

function

bulletpool:initialize()

--快取子彈的table

self.mbulletpool ={}

end

是不是覺得很簡單,是的,lua版本的資源池可以只需要用乙個table就簡單的表示,接下來,我們只需要維護好這個table即可。首先是取子彈的介面:

function

bulletpool:getbullet()

--如果沒有定義,則執行一次兜底定義

ifnot self.mbulletpool then

self.mbulletpool ={}

end--

如果池子裡面沒有可以取的了,則返回nil

ifnext(self.mbulletpool) == nil

then

return

nilend

local bulletobj = self.mbulletpool[#self.mbulletpool]

table.remove(self.mbulletpool, #self.mbulletpool)

return

bulletobj

end

有了設計的介面,接下來,我們可以繼續設計歸還的介面,所謂有借有還再借不難,不能只從池子裡面取,不歸還,那池子早晚會乾涸的 :d

function

bulletpool:insertbullet(bullet)

ifnot bullet then

return

endif

not self.mbulletpool then

self.mbulletpool ={}

end--

子彈歸還前的釋放操作,可以不在意這一步操作

bullet:release()

table.insert

(self.mbulletpool, bullet)

end

好了,有了整體的獲取和歸還的操作,池子的基本介面就有了,有的同學會說,如果我們想重置一遍池子怎麼辦?那就再寫乙個清除池子的操作吧 :b

function

bulletpool:release()

for k, v in

pairs(self.mbulletpool) do

v:release()

endfor k, v in

pairs(self.mbulletpool) do

self.mbulletpool[k] = nil

endend

這下介面都有了,讓我們來應用這些介面吧 :d

首先給角色掛載乙個子彈的資源池的獲取介面吧:

--

獲取介面

function

character:getbullet()

return

bulletpool:getbullet()

end--

塞入介面

function

character:removebullet(bullet)

bulletpool:insertbullet(bullet)

end

因為每個角色都會射出一堆的子彈,所以我們是直接掛在角色身上,就不在整個場景管理器中去管理子彈了,可以通過場景管理器的更新來執行角色的更新,從而執行所有子彈的更新,這樣每個角色的子彈更新和角色更新一致。這種設計模式下,不會出現先更新角色,然後再更新子彈的帶來的一些問題。

有了這兩個介面,下面就是讓角色呼叫這2個介面:

...

--獲取子彈

local bullet =mchar:getbullet()

--沒有則新建,有則重新初始化相關引數

if bullet == nil

then

bullet =bullet:new(...)

else

bullet:initialize(...)

end--

塞入到角色身上的乙個table中維護

mchar:addbullet()

...--

移除子彈,比較簡單

if bullet:update() then

mchar:removebullet(bullet)

end

到這兒,我們完成了乙個簡單的lua版本的資源池的設計和實現,通過這幾個介面,對資源池有乙個簡單的入門理解了。接下來,我們進一步編寫乙個c#版本的資源池吧。

2、c#版本的資源池

在有了lua版本的資源池入門之後,接下來我們可以進一步的設計乙個c#版本的資源池了。在unity的c#中,會有各種各樣的資源需要資源池來進行管理,所以我們不能單獨的做某個類的資源池了,我們需要引入泛型來指代各種型別的資源池。

先寫乙個簡單的資源池,就實現乙個獲取和歸還介面吧:

using

system.collections;

using

system.collections.generic;

public

class objectpoolwhere t:class

return

null

; }

public

void

returnobj(t obj)

} }

有了簡化版本的資源池,我們可以進一步的拓展這個池子的設計。首先,我們可以將鍊錶改為堆疊,用乙個棧來代替鍊錶,相對會比較容易控制,只需要管理入棧和出棧即可。其次,在池子已經被榨乾,取完的時候,前面是直接返回乙個null,我們可以繼續拓展,在沒有的時候,就進行一次建立操作,這個可以通過委託來實現,在池子的初始化的時候就註冊相關的委託。同理,進一步的拓展出取完後的操作和歸還釋放時的操作委託,這樣就把我們前面lua中歸還池子時候釋放子彈的操作封裝為乙個事件。說完思路,下面讓我們開始吧:

using

system;

using

system.collections.generic;

public

class objectpoolwhere t:class

//獲取介面

public

t get()

else

//執行**

if(m_acitononget != null

)

return

obj;

}//釋放介面

public

void

release(t obj)

m_stack.push(obj);

}//clear介面

public

void

clear()

}

寫到這兒,乙個基本的資源池的構建算是完成了,大家可以在這個版本的基礎上進一步的衍生出資源池的使用,比如給資源池的物件新增乙個計時的功能,當資源計時超過一定的時間後,就將其從資源池中去除,避免資源池不斷擴大。諸如此類種種,都是後續可以操作的,好了,這篇文章就寫到這兒,也祝提前祝大家2023年新年快樂!

遊戲引擎 資源管理 記憶體池設計(1)

資源管理包括兩個部分 記憶體管理 資源的記憶體分配 日誌管理 資源的資訊,記憶體資訊都將被記錄在日誌中 資源管理 統一資源 很簡單的記憶體池設計 ifndef cmemorypool h h define cmemorypool h h define null 0 templateclass cme...

遊戲中的資源包

現在的遊戲中一般都有自己的資源包。早期看到很多2d遊戲都沒有資源包的,資源都是分散著的,當然可以直接看到其中每個檔案的內容。後來發現很多遊戲都有資源包了,像天下貳 劍網三等等。下面說說一些遊戲的資源包 1.天龍八部on line 天龍八部的資源在沒有加密前是很容易提取出來的。天龍八部是我最早知道使用...

Unity 提取遊戲資源之ktx轉換

從雨松的博文 unity3d研究院之mac上從.ipa中提取unity3d遊戲資源 六十六 可以學到提取unity的遊戲資源,其中有用到乙個工具 pvrtextool 提取出來的資源,其中的ktx資源,用pvrtextoolgui.exe可以開啟檢視,可以發現都是上下顛倒,且被拉伸 直接轉為png格...