一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

node.js|vue.js|jquery|angularjs|React|json|js教程|

服務(wù)器之家 - 編程語(yǔ)言 - JavaScript - js教程 - 如何使用CocosCreator對(duì)象池

如何使用CocosCreator對(duì)象池

2022-03-01 16:50戰(zhàn) 勝 js教程

這篇文章主要介紹了CocosCreator對(duì)象池,對(duì)性能有研究的同學(xué),要著重看一下

前言:

在運(yùn)行時(shí)進(jìn)行節(jié)點(diǎn)的創(chuàng)建( cc.instantiate )和銷毀( node.destroy )操作是非常耗費(fèi)性能的,因此我們?cè)诒容^復(fù)雜的場(chǎng)景中,通常只有在場(chǎng)景初始化邏輯( onLoad )中才會(huì)進(jìn)行節(jié)點(diǎn)的創(chuàng)建,在切換場(chǎng)景時(shí)才會(huì)進(jìn)行節(jié)點(diǎn)的銷毀。如果制作有大量敵人或子彈需要反復(fù)生成和被消滅的動(dòng)作類游戲,我們要如何在游戲進(jìn)行過(guò)程中隨時(shí)創(chuàng)建和銷毀節(jié)點(diǎn)呢?這里就需要對(duì)象池的幫助了。

對(duì)象池就是一組可回收的節(jié)點(diǎn)對(duì)象,我們通過(guò)創(chuàng)建cc.NodePool的實(shí)例來(lái)初始化一種節(jié)點(diǎn)的對(duì)象池。通常當(dāng)我們有多個(gè) prefab 需要實(shí)例化時(shí),應(yīng)該為每個(gè) prefab 創(chuàng)建一個(gè) cc.NodePool 實(shí)例。

當(dāng)我們需要?jiǎng)?chuàng)建節(jié)點(diǎn)時(shí),向?qū)ο蟪厣暾?qǐng)一個(gè)節(jié)點(diǎn),如果對(duì)象池里有空閑的可用節(jié)點(diǎn),就會(huì)把節(jié)點(diǎn)返回給用戶,用戶通過(guò)node.addChild將這個(gè)新節(jié)點(diǎn)加入到場(chǎng)景節(jié)點(diǎn)樹中。
當(dāng)我們需要銷毀節(jié)點(diǎn)時(shí),調(diào)用對(duì)象池實(shí)例的put(node) 方法,傳入需要銷毀的節(jié)點(diǎn)實(shí)例,對(duì)象池會(huì)自動(dòng)完成把節(jié)點(diǎn)從場(chǎng)景節(jié)點(diǎn)樹中移除的操作,然后返回給對(duì)象池。

這樣就實(shí)現(xiàn)了少數(shù)節(jié)點(diǎn)的循環(huán)利用。

具體操作

第一步:準(zhǔn)備好 Prefab

把你想要?jiǎng)?chuàng)建的節(jié)點(diǎn)事先設(shè)置好并做成 Prefab 資源,有些朋友可能不會(huì)制作預(yù)制體?
(只需要將資源管理器里的資源 拉拽到 層級(jí)管理器中 然后 將節(jié)點(diǎn)在拉拽回 資源管理器)
這樣就完成預(yù)制體的創(chuàng)建了!

第二步:初始化對(duì)象池

在場(chǎng)景加載的初始化腳本中,我們可以將需要數(shù)量的節(jié)點(diǎn)創(chuàng)建出來(lái),并放進(jìn)對(duì)象池:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
properties: {
    enemyPrefab: cc.Prefab  // 所需要的預(yù)制體
},
onLoad: function () {
    //  創(chuàng)建對(duì)象池
    this.enemyPool = new cc.NodePool();
    
    let initCount = 5;
    for (let i = 0; i < initCount; ++i) {
        let enemy = cc.instantiate(this.enemyPrefab); // 創(chuàng)建節(jié)點(diǎn)
        this.enemyPool.put(enemy); // 通過(guò) put 接口放入對(duì)象池
    }
}

對(duì)象池里需要的初始節(jié)點(diǎn)數(shù)量可以根據(jù)游戲的需要來(lái)控制,即使我們對(duì)初始節(jié)點(diǎn)數(shù)量的預(yù)估不準(zhǔn)確也不要緊,后面我們會(huì)進(jìn)行處理。

第三步:從對(duì)象池請(qǐng)求對(duì)象

接下來(lái)在我們的運(yùn)行時(shí)代碼中就可以用下面的方式來(lái)獲得對(duì)象池中儲(chǔ)存的對(duì)象了:

?
1
2
3
4
5
6
7
8
9
10
11
12
createEnemy: function (parentNode) {
    let enemy = null;
    if (this.enemyPool.size() > 0) { // 通過(guò) size 接口判斷對(duì)象池中是否有空閑的對(duì)象
        // get()獲取對(duì)象
        enemy = this.enemyPool.get();
        
    } else { // 如果沒(méi)有空閑對(duì)象,也就是對(duì)象池中備用對(duì)象不夠時(shí),我們就用 cc.instantiate 重新創(chuàng)建
        enemy = cc.instantiate(this.enemyPrefab);
    }
    enemy.parent = parentNode; // 將生成的敵人加入節(jié)點(diǎn)樹
    enemy.getComponent('Enemy').init(); //接下來(lái)就可以調(diào)用 enemy 身上的腳本進(jìn)行初始化
}

安全使用對(duì)象池的要點(diǎn)就是在 get 獲取對(duì)象之前,永遠(yuǎn)都要先用 size 來(lái)判斷是否有可用的對(duì)象,如果沒(méi)有就使用正常創(chuàng)建節(jié)點(diǎn)的方法,雖然會(huì)消耗一些運(yùn)行時(shí)性能,但總比游戲崩潰要好!另一個(gè)選擇是直接調(diào)用 get ,如果對(duì)象池里沒(méi)有可用的節(jié)點(diǎn),會(huì)返回 null ,在這一步進(jìn)行判斷也可以。

第四步:將對(duì)象返回對(duì)象池

當(dāng)我們殺死敵人時(shí),需要將敵人節(jié)點(diǎn)退還給對(duì)象池,以備之后繼續(xù)循環(huán)利用,我們用這樣的方法:

?
1
2
3
4
onEnemyKilled: function (enemy) {
    // enemy 應(yīng)該是一個(gè) cc.Node
    this.enemyPool.put(enemy); // 和初始化時(shí)的方法一樣,將節(jié)點(diǎn)放進(jìn)對(duì)象池,這個(gè)方法會(huì)同時(shí)調(diào)用節(jié)點(diǎn)的 removeFromParent
}

這樣我們就完成了一個(gè)完整的循環(huán),主角需要刷多少怪都不成問(wèn)題了!將節(jié)點(diǎn)放入和從對(duì)象池取出的操作不會(huì)帶來(lái)額外的內(nèi)存管理開(kāi)銷,因此只要是可能,應(yīng)該盡量去利用。

第五步:使用組件來(lái)處理回收和復(fù)用的事件

使用構(gòu)造函數(shù)創(chuàng)建對(duì)象池時(shí),可以指定一個(gè)組件類型或名稱,作為掛載在節(jié)點(diǎn)上用于處理節(jié)點(diǎn)回收和復(fù)用事件的組件。

在創(chuàng)建對(duì)象池時(shí)可以用:

?
1
let menuItemPool = new cc.NodePool('MenuItem');  // 指定一個(gè)組件類型

這樣當(dāng)使用 menuItemPool.get() 獲取節(jié)點(diǎn)后,就會(huì)調(diào)用 MenuItem 里的 reuse方法,完成點(diǎn)擊事件的注冊(cè)。
當(dāng)使用menuItemPool.put(menuItemNode)回收節(jié)點(diǎn)后,會(huì)調(diào)用 MenuItem 里的 unuse方法,完成點(diǎn)擊事件的反注冊(cè)。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
cc.Class({
    extends: cc.Component,
    onLoad: function () {
        this.node.selected = false;
        this.node.on(cc.Node.EventType.TOUCH_END, this.onSelect, this.node);
    },
    // put() 收回對(duì)象池時(shí)會(huì)調(diào)用
    unuse: function () {
        this.node.off(cc.Node.EventType.TOUCH_END, this.onSelect, this.node);
    },
    // get()獲取對(duì)象池內(nèi)對(duì)象時(shí)會(huì)調(diào)用
    reuse: function () {
        this.node.on(cc.Node.EventType.TOUCH_END, this.onSelect, this.node);
    }
});

另外 cc.NodePool.get() 可以傳入任意數(shù)量類型的參數(shù),這些參數(shù)會(huì)被原樣傳遞給 reuse 方法:

?
1
2
3
4
5
6
7
8
9
10
11
// BulletManager.js
let myBulletPool = new cc.NodePool('Bullet'); //創(chuàng)建子彈對(duì)象池
let newBullet = myBulletPool.get(this); // 傳入 manager 的實(shí)例,用于之后在子彈腳本中回收子彈
 
// Bullet.js
reuse (bulletManager) {
    this.bulletManager = bulletManager; // get 中傳入的管理類實(shí)例
}
hit () {
    this.bulletManager.put(this.node); // 通過(guò)之前傳入的管理類實(shí)例回收子彈
}

第六步:清除對(duì)象池

如果對(duì)象池中的節(jié)點(diǎn)不再被需要,我們可以手動(dòng)清空對(duì)象池,銷毀其中緩存的所有節(jié)點(diǎn):

?
1
myPool.clear(); // 調(diào)用這個(gè)方法就可以清空對(duì)象池

當(dāng)對(duì)象池實(shí)例不再被任何地方引用時(shí),引擎的垃圾回收系統(tǒng)會(huì)自動(dòng)對(duì)對(duì)象池中的節(jié)點(diǎn)進(jìn)行銷毀和回收。但這個(gè)過(guò)程的時(shí)間點(diǎn)不可控,另外如果其中的節(jié)點(diǎn)有被其他地方所引用,也可能會(huì)導(dǎo)致內(nèi)存泄露,所以最好在切換場(chǎng)景或其他不再需要對(duì)象池的時(shí)候手動(dòng)調(diào)用 clear 方法來(lái)清空緩存節(jié)點(diǎn)。

以上就是如何使用CocosCreator對(duì)象池的詳細(xì)內(nèi)容,更多關(guān)于CocosCreator對(duì)象池的資料請(qǐng)關(guān)注服務(wù)器之家其它相關(guān)文章!

原文鏈接:https://blog.csdn.net/qq_45021180/article/details/104484744

延伸 · 閱讀

精彩推薦
  • js教程不用typsescript如何使用類型增強(qiáng)功能

    不用typsescript如何使用類型增強(qiáng)功能

    這篇文章主要給大家介紹了關(guān)于不用typsescript如何使用類型增強(qiáng)功能的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參...

    小云菜7982022-02-12
  • js教程微信小程序+mqtt,esp8266溫濕度讀取的實(shí)現(xiàn)方法

    微信小程序+mqtt,esp8266溫濕度讀取的實(shí)現(xiàn)方法

    這篇文章主要介紹了微信小程序+mqtt,esp8266溫濕度讀取的實(shí)現(xiàn)方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友...

    巴法云6062022-02-22
  • js教程JavaScript實(shí)現(xiàn)切換多張圖片

    JavaScript實(shí)現(xiàn)切換多張圖片

    這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)切換多張圖片,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下...

    是M11772022-01-10
  • js教程JavaScript實(shí)現(xiàn)點(diǎn)擊出現(xiàn)子菜單效果

    JavaScript實(shí)現(xiàn)點(diǎn)擊出現(xiàn)子菜單效果

    這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)點(diǎn)擊出現(xiàn)子菜單,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下...

    weixin_551084226462022-01-19
  • js教程基于JS繪制2021的煙花效果 附源碼下載

    基于JS繪制2021的煙花效果 附源碼下載

    這篇文章主要介紹了基于JS繪制2021的煙花效果,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下...

    3512022-02-17
  • js教程JS實(shí)現(xiàn)隨機(jī)點(diǎn)名系統(tǒng)

    JS實(shí)現(xiàn)隨機(jī)點(diǎn)名系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了JS實(shí)現(xiàn)隨機(jī)點(diǎn)名系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下...

    乘風(fēng)破浪的程序媛3592022-02-22
  • js教程JavaScript 繪制餅圖的示例

    JavaScript 繪制餅圖的示例

    這篇文章主要介紹了JavaScript 繪制餅圖的示例,幫助大家更好的利用JavaScript繪制圖表,感興趣的朋友可以了解下...

    MwqgKG11442022-01-21
  • js教程詳解ES6實(shí)現(xiàn)類的私有變量的幾種寫法

    詳解ES6實(shí)現(xiàn)類的私有變量的幾種寫法

    這篇文章主要介紹了詳解ES6實(shí)現(xiàn)類的私有變量的幾種寫法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋...

    Do_Better11932022-01-20
主站蜘蛛池模板: 成年男人永久免费看片 | 男人天堂色 | 亚洲国产精品网站久久 | 四虎成人免费视频 | 国产在线观看网站 | 日韩在线毛片 | 欧美丝袜videohd | 奇米影视在线观看 | 亚洲AV国产精品无码精 | 天天乐影院 | 免费观看视频高清在线 | 俄罗斯美女破苞 | 久久久久免费视频 | 97青草 | 四虎在线播放 | 男人和女人日 | 免费国产一级观看完整版 | 精品久久洲久久久久护士免费 | 国产亚洲女在线线精品 | 加勒比一本大道香蕉在线视频 | 成人黄页网站 | 日岳母小说 | 国产最新精品视频 | 精品一区二区三区免费毛片 | 日本高清中文 | 久久久久久免费高清电影 | 国产图片综合区 | 97啪啪| 久久久精品成人免费看 | 国产一区二区视频在线 | caoporm碰最新免费公开视频 | 好大好猛好爽好深视频免费 | 欧美a级完整在线观看 | chinesegay黑袜玩奴 | 色中色导航 | 东北疯狂xxxxbbbb中国 | 青青草亚洲 | 国产精品主播在线 | 能播放的欧美同性videos | 天天操婷婷 | 男女乱淫真视频播放网站 |