Cocos Creator 使用对象池(摘自官方文档)
使用对象池 在运行时进行节点的创建( 对象池的概念 对象池就是一组可回收的节点对象,我们通过创建 当我们需要销毁节点时,调用对象池实例的 关于 流程介绍下面是使用对象池的一般工作流程 准备好 Prefab把你想要创建的节点事先设置好并做成 Prefab 资源,方法请查看预制资源工作流程。 初始化对象池在场景加载的初始化脚本中,我们可以将需要数量的节点创建出来,并放进对象池: //...
properties: {
enemyPrefab: cc.Prefab
},onLoad: function () {
this.enemyPool = new cc.NodePool();
let initCount = 5;
for (let i = 0; i < initCount; ++i) {
let enemy = cc.instantiate(this.enemyPrefab); // 创建节点
this.enemyPool.put(enemy); // 通过 putInPool 接口放入对象池
}
}
对象池里需要的初始节点数量可以根据游戏的需要来控制,即使我们对初始节点数量的预估不准确也不要紧,后面我们会进行处理。 从对象池请求对象接下来在我们的运行时代码中就可以用下面的方式来获得对象池中储存的对象了: // ...
createEnemy: function (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 身上的脚本进行初始化
}
安全使用对象池的要点就是在 将对象返回对象池当我们杀死敌人时,需要将敌人节点退还给对象池,以备之后继续循环利用,我们用这样的方法: // ...
onEnemyKilled: function (enemy) {
// enemy 应该是一个 cc.Node
this.enemyPool.put(enemy); // 和初始化时的方法一样,将节点放进对象池,这个方法会同时调用节点的 removeFromParent
}
这样我们就完成了一个完整的循环,主角需要刷多少怪都不成问题了!将节点放入和从对象池取出的操作不会带来额外的内存管理开销,因此只要是可能,应该尽量去利用。 使用组件来处理回收和复用的事件 使用构造函数创建对象池时,可以指定一个组件类型或名称,作为挂载在节点上用于处理节点回收和复用事件的组件。假如我们有一组可点击的菜单项需要做成对象池,每个菜单项上有一个 // MenuItem.js
cc.Class({
extends: cc.Component,onLoad: function () {
this.node.selected = false;
this.node.on(cc.Node.EventType.TOUCH_END,this.onSelect.bind(this),this.node);
},unuse: function () {
this.node.off(cc.Node.EventType.TOUCH_END,reuse: function () {
this.node.on(cc.Node.EventType.TOUCH_END,this.node);
}
});
在创建对象池时可以用: 这样当使用 另外 // BulletManager.js
let myBulletPool = new cc.NodePool('Bullet'); //创建子弹对象池
...
let newBullet = myBulletPool.get(this); // 传入 manager 的实例,用于之后在子弹脚本中回收子弹
// Bullet.js
reuse (bulletManager) {
this.bulletManager = bulletManager; // get 中传入的管理类实例
}
hit () {
// ...
this.bulletManager.put(this.node); // 通过之前传入的管理类实例回收子弹
}
清除对象池如果对象池中的节点不再被需要,我们可以手动清空对象池,销毁其中缓存的所有节点: myPool.clear(); // 调用这个方法就可以清空对象池
当对象池实例不再被任何地方引用时,引擎的垃圾回收系统会自动对对象池中的节点进行销毁和回收。但这个过程的时间点不可控,另外如果其中的节点有被其他地方所引用,也可能会导致内存泄露,所以最好在切换场景或其他不再需要对象池的时候手动调用 使用 cc.NodePool 的优势cc.NodePool除了可以创建多个对象池实例,同一个 prefab 也可以创建多个对象池,每个对象池中用不同参数进行初始化,大大增强了灵活性;此外 而之前的 对象池的基本功能其实非常简单,就是使用数组来保存已经创建的节点实例列表。如果有其他更复杂的需求,你也可以参考暗黑斩 Demo 中的 PoolMng 脚本来实现自己的对象池。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |