creator2.2.0性能测试:创建1000个对象后删除

creator2.2.0: 先初始化创建1000个sprite node放入对象池, 再从对象池中创建500个对象加入场景, 再使用nodepool的put方法删除100个对象,界面直接卡主几秒。

1赞

cc.Class({
extends: cc.Component,

properties: {
    enemyPrefab: cc.Prefab,
    enemyNodes: cc.Node,
},

// LIFE-CYCLE CALLBACKS:

onLoad() {
    cc.director.getCollisionManager().enabled = true;
    this.initNodePools();
},

onBtn1() {
    for (let i = 0; i < 500; ++i) {
        let node = this.createEnemy(this.enemyNodes);

        node.x = require("GameUtils").randomNumber(-cc.winSize.width / 2, cc.winSize.width / 2);
        node.y = require("GameUtils").randomNumber(-cc.winSize.height / 2, cc.winSize.height / 2);
    }

    let allNodes = this.enemyNodes.children;

    setTimeout(() => {
        let temp = [];
        for (let i = 0; i < 100; ++i) {
            let rand = require("GameUtils").randomNumber(0, allNodes.length - 1);
            temp.push(rand);
        }
        cc.log('temp=' + temp);
        console.time("onEnemyKilled");
        for (let i = 0; i < temp.length; ++i) {
            let node = allNodes[temp[i]];
            this.onEnemyKilled(node);
        }
        console.timeEnd("onEnemyKilled");
        
    }, 500);
},

/**
 * 初始化对象池
 */
initNodePools() {
    console.time("initNodePools");
    this.enemyPool = new cc.NodePool('enemy');

    for (let i = 0; i < 1000; ++i) {
        let node = cc.instantiate(this.enemyPrefab); // 创建节点
        this.enemyPool.put(node); // 通过 put 接口放入对象池
    }
    console.timeEnd("initNodePools");
},

createEnemy(parentNode) {
    let enemy = null;
    if (this.enemyPool.size() > 0) { // 通过 size 接口判断对象池中是否有空闲的对象
        enemy = this.enemyPool.get();
    } else { // 如果没有空闲对象,也就是对象池中备用对象不够时,我们就用 cc.instantiate 重新创建
        enemy = cc.instantiate(this.enemyPrefab);
    }
    enemy.parent = parentNode; // 将生成的敌人加入节点树
    enemy.getComponent('Enemy').init(); //接下来就可以调用 enemy 身上的脚本进行初始化
    return enemy;
},

onEnemyKilled: function (enemy) {
    // enemy 应该是一个 cc.Node
    //enemy.x = 10001;
    this.enemyPool.put(enemy); // 和初始化时的方法一样,将节点放进对象池,这个方法会同时调用节点的 removeFromParent
}

});

卡主时间: onEnemyKilled: 2613.4677734375ms

我没有测试之前的版本是否也是这样,还是我的写法有问题?

我发现实质是: 先创建很多对象node, 然后再设置其中一些node.active = false; 这一步操作就很费时间。

这个问题我们会在 2.2.1 优化,谢谢反馈!

谢谢大佬的回复! 好像这个我试了之前的版本也是这样的,就是随便创建500个简单的Sprite对象, 然后隐藏其中50个对象, 就会卡一下。

上面实验中我的每个对象都有一个boxcollider, 所以导致node.active = false的时候很卡, 去掉boxcollider后就不卡了。。。

调用active就会卡,不要active

我实验出主要是boxcollider引起的, 绑定了boxcollider的对象node.active=false, 性能不行, 随便创建100个对象,然后设置隐藏就卡主了; 去掉boxcollider后,瞬间流畅了。

还有个坑,是成千个node active 的时候也会卡

说说我的经验吧,都是collider的锅,任何改变collider状态的操作,包括enabled, node active, 修改parent, 更改group都会引起严重的卡顿,试下来的方案是poolMgr 把对象放在看不见的地方,且collider不要有碰撞,否则也有性能问题

1赞

是的, BoxCollider问题很严重, 反而用物理系统里的collider性能还好些, 不过我现在准备自己写代码检测碰撞了。

要自己写一个性能良好的碰撞系统应该还是挺难的。你可以试试这个js裤。
https://github.com/Sinova/Collisions

嗯嗯,我这边只是简单的矩形碰撞检测,比较容易。