Unity編程標準導(dǎo)引-3.4 Unity中的對象池
本節(jié)通過一個簡單的射擊子彈的示例來介紹Transform的用法。子彈射擊本身很容易制作,只要制作一個子彈Prefab,再做一個發(fā)生器,使用發(fā)生器控制按頻率產(chǎn)生子彈,即克隆子彈Prefab,然后為每個子彈寫上運動邏輯就可以了。這本該是很簡單的事情。不過問題來了,發(fā)射出去后的子彈如何處理?直接Destroy嗎?這太浪費了,要知道Unity的Mono內(nèi)存是不斷增長的。就是說出了Unity內(nèi)部的那些網(wǎng)格、貼圖等等資源內(nèi)存(簡單說就是繼承自UnityEngine下的Object的那些類),而我們自己寫的C#代碼繼承自System下的Object,這些代碼產(chǎn)生的內(nèi)存即是Mono內(nèi)存,它只增不減。同樣,你不斷Destroy你的Unity對象也是要消耗性能去進行回收,而子彈這種消耗品實在產(chǎn)生的太快了,我們必需加以控制。
那么,我們?nèi)绾慰刂剖沟貌恢劣诓粩喈a(chǎn)生新的內(nèi)存呢?答案就是自己寫內(nèi)存池。自己回收利用之前創(chuàng)建過的對象。所以這個章節(jié)的內(nèi)容,我們將重點放在寫一個比較好的內(nèi)存池上。就我自己來講,在寫一份較為系統(tǒng)的功能代碼之前,我考慮的首先不是這個框架是該如何的,而是從使用者的角度去考慮,這個代碼如何寫使用起來才會比較方便,同樣也要考慮容易擴展、通用性強、比較安全、減少耦合等等。
3.4.1、從使用者視角給出需求
首先,我所希望的這個內(nèi)存池的代碼最后使用應(yīng)該是這樣的。
Bullet a = Pool.Take<Bullet>(); //從池中立刻獲取一個單元,如果單元不存在,則它需要為我立刻創(chuàng)建出來。返回一個Bullet腳本以便于后續(xù)控制。注意這里使用泛型,也就是說它應(yīng)該可以兼容任意的腳本類型。
Pool.restore(a);//當使用完成Bullet之后,我可以使用此方法回收這個對象。注意這里實際上我已經(jīng)把Bullet這個組件的回收等同于某個GameObject(這里是子彈的GameObject)的回收。
使用上就差不多是這樣了,希望可以有極其簡單的方法來進行獲取和回收操作。
3.4.2、內(nèi)存池單元結(jié)構(gòu)
最簡單的內(nèi)存池形式,差不多就是兩個List,一個處于工作狀態(tài),一個處于閑置狀態(tài)。工作完畢的對象被移動到閑置狀態(tài)列表,以便于后續(xù)的再次獲取和利用,形成一個循環(huán)。我們這里也會設(shè)計一個結(jié)構(gòu)來管理這兩個List,用于處理同一類的對象。