【工具】Cocos Creator 对象池(NodePool,自定义预制体对象池)
版本:2.3.4
参考:
NodePool
cocos的NodePool提供了一个数组,保存和获取数组内对象,并在保存和获取时可执行对象上的unuse和reuse方法。
使用相对简单,看看cocos教程即可。
主要是在获取对象池中实例时,不存在实例,则返回null,不会自动新建。 新建的代码得自己写。
cocos对象池源码
CCNodePool.js:
cc.NodePool = function (poolHandlerComp) { this.poolHandlerComp = poolHandlerComp; this._pool = []; }; cc.NodePool.prototype = { constructor: cc.NodePool, size: function () { return this._pool.length; }, clear: function () { var count = this._pool.length; for (var i = 0; i < count; ++i) { this._pool[i].destroy(); } this._pool.length = 0; }, put: function (obj) { if (obj && this._pool.indexOf(obj) === -1) { // Remove from parent, but don\'t cleanup obj.removeFromParent(false); // Invoke pool handler var handler = this.poolHandlerComp ? obj.getComponent(this.poolHandlerComp) : null; if (handler && handler.unuse) { handler.unuse(); } this._pool.push(obj); } }, get: function () { var last = this._pool.length-1; if (last < 0) { return null; } else { // Pop the last object in pool var obj = this._pool[last]; this._pool.length = last; // Invoke pool handler var handler = this.poolHandlerComp ? obj.getComponent(this.poolHandlerComp) : null; if (handler && handler.reuse) { handler.reuse.apply(handler, arguments); } return obj; } } }; module.exports = cc.NodePool;
PrefabPool
我自己写了一个针对prefab的对象池。有以下的改进。
1. 全局调用,不需要在使用的地方去new cc.NodePool
2. 在对象池没有缓存实体时,会自动创建并返回实体
3. 对象回收时,根据创建时动态属性poolKey找到对应池子回收
4. 保留了NodePool的unuse和reuse
// Learn TypeScript: // - https://docs.cocos.com/creator/manual/en/scripting/typescript.html // Learn Attribute: // - https://docs.cocos.com/creator/manual/en/scripting/reference/attributes.html // Learn life-cycle callbacks: // - https://docs.cocos.com/creator/manual/en/scripting/life-cycle-callbacks.html const { ccclass, property } = cc._decorator; /** * 预制体对象池 * @author chenkai 2020.6.11 */ @ccclass export default class PrefabPool { /**对象池列表 */ private static poolList = {}; /** * 获取对象 * @param prefabUrl 预制体路径 * @param poolHandlerComp reuse绑定函数 */ public static get(prefabUrl:string, poolHandlerComp:Function = null){ //创建对象池数组 if(this.poolList[prefabUrl] == null){ this.poolList[prefabUrl] = []; } //从对象池获取对象,没有则创建 let pool = this.poolList[prefabUrl]; let obj; if (pool.length == 0) { obj = cc.instantiate(cc.loader.getRes(prefabUrl)); (obj as any).poolKey = prefabUrl; }else{ obj = pool.pop(); } //执行reuse var handler = poolHandlerComp ? obj.getComponent(poolHandlerComp) : null; if (handler && handler.reuse) { handler.reuse.apply(handler, arguments); } //返回对象 return obj; } /** * 回收对象 * @param obj 实体 * @param poolHandlerComp unuse绑定函数 */ public static put(obj:cc.Node, poolHandlerComp:Function = null){ let pool = this.poolList[(obj as any).poolKey]; //判断对象池存在 if (pool && pool.indexOf(obj) == -1) { //移除舞台 obj.removeFromParent(false); //执行unuse var handler = poolHandlerComp ? obj.getComponent(poolHandlerComp) : null; if (handler && handler.unuse) { handler.unuse(); } //存放对象 pool.push(obj); } } /** * 清理对象池 * @param prefabUrl 预制体路径 */ public static clear(prefabUrl:string){ let pool = this.poolList[prefabUrl]; if(pool){ for (let i = 0,len=pool.length; i < len; i++) { pool[i].destroy(); } pool.length = 0; } } /**清理所有对象池 */ public static clearAll(){ for(let key in this.poolList){ this.clear(key); } } /** * 对象池长度 * @param prefabUrl 预制体路径 */ public static size(prefabUrl:string) { let pool = this.poolList[prefabUrl]; if(pool){ return pool.length; } return 0; } }
使用
export class PrefabConst{ public static Monster001:string = "game/prefab/monster001";//预制体路径 public static Mosnter002:string = "game/prefab/monster002"; } export class GameScene{ onLoad(){ //获取对象 let node001:cc.Node = PrefabPool.get(PrefabConst.Monster001,Monster); let monster001:Monster = node.getComponent(Monster); let node002:cc.Node = PrefabPool.get(PrefabConst.Monster002,Monster); let monster002:Monster = node.getComponent(Monster); //回收对象 PrefabPool.put(node001,Monster); PrefabPool.put(node002,Monster); //清理对象 PrefabPool.clear(PrefabConst.Monster001); PrefabPool.clearAll(); } }