如何使用CocosCreator對象池
前言:
在運行時進(jìn)行節(jié)點的創(chuàng)建( cc.instantiate )和銷毀( node.destroy )操作是非常耗費性能的,因此我們在比較復(fù)雜的場景中,通常只有在場景初始化邏輯( onLoad )中才會進(jìn)行節(jié)點的創(chuàng)建,在切換場景時才會進(jìn)行節(jié)點的銷毀。如果制作有大量敵人或子彈需要反復(fù)生成和被消滅的動作類游戲,我們要如何在游戲進(jìn)行過程中隨時創(chuàng)建和銷毀節(jié)點呢?這里就需要對象池的幫助了。
對象池就是一組可回收的節(jié)點對象,我們通過創(chuàng)建cc.NodePool的實例來初始化一種節(jié)點的對象池。通常當(dāng)我們有多個 prefab 需要實例化時,應(yīng)該為每個 prefab 創(chuàng)建一個 cc.NodePool 實例。
當(dāng)我們需要創(chuàng)建節(jié)點時,向?qū)ο蟪厣暾堃粋€節(jié)點,如果對象池里有空閑的可用節(jié)點,就會把節(jié)點返回給用戶,用戶通過node.addChild將這個新節(jié)點加入到場景節(jié)點樹中。
當(dāng)我們需要銷毀節(jié)點時,調(diào)用對象池實例的put(node) 方法,傳入需要銷毀的節(jié)點實例,對象池會自動完成把節(jié)點從場景節(jié)點樹中移除的操作,然后返回給對象池。
這樣就實現(xiàn)了少數(shù)節(jié)點的循環(huán)利用。
具體操作
第一步:準(zhǔn)備好 Prefab
把你想要創(chuàng)建的節(jié)點事先設(shè)置好并做成 Prefab 資源,有些朋友可能不會制作預(yù)制體?
(只需要將資源管理器里的資源 拉拽到 層級管理器中 然后 將節(jié)點在拉拽回 資源管理器)
這樣就完成預(yù)制體的創(chuàng)建了!
第二步:初始化對象池
在場景加載的初始化腳本中,我們可以將需要數(shù)量的節(jié)點創(chuàng)建出來,并放進(jìn)對象池:
properties: { enemyPrefab: cc.Prefab // 所需要的預(yù)制體 }, onLoad: function () { // 創(chuàng)建對象池 this.enemyPool = new cc.NodePool(); let initCount = 5; for (let i = 0; i < initCount; ++i) { let enemy = cc.instantiate(this.enemyPrefab); // 創(chuàng)建節(jié)點 this.enemyPool.put(enemy); // 通過 put 接口放入對象池 } }
對象池里需要的初始節(jié)點數(shù)量可以根據(jù)游戲的需要來控制,即使我們對初始節(jié)點數(shù)量的預(yù)估不準(zhǔn)確也不要緊,后面我們會進(jìn)行處理。
第三步:從對象池請求對象
接下來在我們的運行時代碼中就可以用下面的方式來獲得對象池中儲存的對象了:
createEnemy: function (parentNode) { let enemy = null; if (this.enemyPool.size() > 0) { // 通過 size 接口判斷對象池中是否有空閑的對象 // get()獲取對象 enemy = this.enemyPool.get(); } else { // 如果沒有空閑對象,也就是對象池中備用對象不夠時,我們就用 cc.instantiate 重新創(chuàng)建 enemy = cc.instantiate(this.enemyPrefab); } enemy.parent = parentNode; // 將生成的敵人加入節(jié)點樹 enemy.getComponent('Enemy').init(); //接下來就可以調(diào)用 enemy 身上的腳本進(jìn)行初始化 }
安全使用對象池的要點就是在 get 獲取對象之前,永遠(yuǎn)都要先用 size 來判斷是否有可用的對象,如果沒有就使用正常創(chuàng)建節(jié)點的方法,雖然會消耗一些運行時性能,但總比游戲崩潰要好!另一個選擇是直接調(diào)用 get ,如果對象池里沒有可用的節(jié)點,會返回 null ,在這一步進(jìn)行判斷也可以。
第四步:將對象返回對象池
當(dāng)我們殺死敵人時,需要將敵人節(jié)點退還給對象池,以備之后繼續(xù)循環(huán)利用,我們用這樣的方法:
onEnemyKilled: function (enemy) { // enemy 應(yīng)該是一個 cc.Node this.enemyPool.put(enemy); // 和初始化時的方法一樣,將節(jié)點放進(jìn)對象池,這個方法會同時調(diào)用節(jié)點的 removeFromParent }
這樣我們就完成了一個完整的循環(huán),主角需要刷多少怪都不成問題了!將節(jié)點放入和從對象池取出的操作不會帶來額外的內(nèi)存管理開銷,因此只要是可能,應(yīng)該盡量去利用。
第五步:使用組件來處理回收和復(fù)用的事件
使用構(gòu)造函數(shù)創(chuàng)建對象池時,可以指定一個組件類型或名稱,作為掛載在節(jié)點上用于處理節(jié)點回收和復(fù)用事件的組件。
在創(chuàng)建對象池時可以用:
let menuItemPool = new cc.NodePool('MenuItem'); // 指定一個組件類型
這樣當(dāng)使用 menuItemPool.get() 獲取節(jié)點后,就會調(diào)用 MenuItem 里的 reuse方法,完成點擊事件的注冊。
當(dāng)使用menuItemPool.put(menuItemNode)回收節(jié)點后,會調(diào)用 MenuItem 里的 unuse方法,完成點擊事件的反注冊。
cc.Class({ extends: cc.Component, onLoad: function () { this.node.selected = false; this.node.on(cc.Node.EventType.TOUCH_END, this.onSelect, this.node); }, // put() 收回對象池時會調(diào)用 unuse: function () { this.node.off(cc.Node.EventType.TOUCH_END, this.onSelect, this.node); }, // get()獲取對象池內(nèi)對象時會調(diào)用 reuse: function () { this.node.on(cc.Node.EventType.TOUCH_END, this.onSelect, this.node); } });
另外 cc.NodePool.get() 可以傳入任意數(shù)量類型的參數(shù),這些參數(shù)會被原樣傳遞給 reuse 方法:
// BulletManager.js let myBulletPool = new cc.NodePool('Bullet'); //創(chuàng)建子彈對象池 let newBullet = myBulletPool.get(this); // 傳入 manager 的實例,用于之后在子彈腳本中回收子彈 // Bullet.js reuse (bulletManager) { this.bulletManager = bulletManager; // get 中傳入的管理類實例 } hit () { this.bulletManager.put(this.node); // 通過之前傳入的管理類實例回收子彈 }
第六步:清除對象池
如果對象池中的節(jié)點不再被需要,我們可以手動清空對象池,銷毀其中緩存的所有節(jié)點:
myPool.clear(); // 調(diào)用這個方法就可以清空對象池
當(dāng)對象池實例不再被任何地方引用時,引擎的垃圾回收系統(tǒng)會自動對對象池中的節(jié)點進(jìn)行銷毀和回收。但這個過程的時間點不可控,另外如果其中的節(jié)點有被其他地方所引用,也可能會導(dǎo)致內(nèi)存泄露,所以最好在切換場景或其他不再需要對象池的時候手動調(diào)用 clear 方法來清空緩存節(jié)點。
以上就是如何使用CocosCreator對象池的詳細(xì)內(nèi)容,更多關(guān)于CocosCreator對象池的資料請關(guān)注腳本之家其它相關(guān)文章!
- 詳解cocoscreater預(yù)制體prefab
- 如何在CocosCreator中利用常駐節(jié)點做圖層管理
- 游戲開發(fā)中如何使用CocosCreator進(jìn)行音效處理
- CocosCreator ScrollView優(yōu)化系列之分幀加載
- 詳解CocosCreator項目結(jié)構(gòu)機制
- CocosCreator如何實現(xiàn)劃過的位置顯示紋理
- 整理CocosCreator常用知識點
- 全面講解CocosCreator熱更新
- CocosCreator經(jīng)典入門項目之flappybird
- CocosCreator通用框架設(shè)計之網(wǎng)絡(luò)
- 如何用CocosCreator實現(xiàn)射擊小游戲
- 怎樣在CocosCreator中使用游戲手柄
相關(guān)文章
JavaScript實現(xiàn)手寫原生任務(wù)定時器
定時器顧名思義就是在某個特定的時間去執(zhí)行一些任務(wù),現(xiàn)代的應(yīng)用程序早已不是以前的那些由簡單的增刪改查拼湊而成的程序了,高復(fù)雜性早已是標(biāo)配,而任務(wù)的定時調(diào)度與執(zhí)行也是對程序的基本要求了。本文將利用JavaScript手寫原生任務(wù)定時器,需要的可以參考一下2022-03-03-
最新評論