Cocos Creator 节点对象池管理器

244 阅读2分钟

在交互及其频繁的游戏场景中,会产生大量的节点创建与销毁,其操作是非常耗费性能的,那么对象池则可以极大减少了重复节点的创建。

对象池就是一组可回收的节点对象,我们通过创建 cc.NodePool 的实例来初始化一种节点的对象池。通常当我们有多个 prefab 需要实例化时,应该为每个 prefab 创建一个 cc.NodePool 实例。当我们需要创建节点时,向对象池申请一个节点,如果对象池里有空闲的可用节点,就会把节点返回给用户,用户通过 node.addChild 将这个新节点加入到场景节点树中。

创建节点管理类

export class PoolManager{    
private poolDic: Dictionary<ObjectPool> = new Dictionary<ObjectPool>();
    public CreatePool(poolName: string, go: Node | Prefab) {
        if (!go || !go.isValid) return warn(" prefab not available ", poolName);
        if (this.poolDic.containsKey(poolName)) return warn(" pool already exists ", poolName);
        let pool = new ObjectPool(go);
        this.poolDic.add(poolName, pool);
    }
    public Get(poolName: string) {
        let pool: ObjectPool = this.poolDic.getValue(poolName);
        if (pool) return pool.Get();
        warn(" pool does not exist , unable to get ");
        return null;
    }    
public Save(poolName: string, go: Node, delay: number = 0, callback?) {
        let pool: ObjectPool = this.poolDic.getValue(poolName);
        if (pool) return pool.Save(go, delay, callback);
        warn(" pool does not exist , unable to save ");
    }    
public SaveAll(poolName: string) {
        let pool: ObjectPool = this.poolDic.getValue(poolName);
        if (pool) return pool.SaveAll();
    }    
public Clean(poolName: string) {
        let pool: ObjectPool = this.poolDic.getValue(poolName);
        if (pool) {
            pool.Clean();
            this.poolDic.remove(poolName);
        }
    }    
public CleanAll() {
        this.poolDic.clear();
    }
}
  • poolDic: 池子承载对象(子弹道具池子、炮弹道具池子等等......)

  • CreatePool:创建某个节点池子,根据poolName区分

  • Get:获取某个节点池子中未活跃的节点,并将状态更新为活跃

  • Save: 将指定某节点的状态更新为不活跃

  • SaveAll:将整个节点池子所有节点变为不活跃

  • Clean:清空某节点池子

  • CleanAll:清空所有节点池子

创建执行节点活跃状态的类

export class ObjectPool {
    private prefab: Node | Prefab;
    private pool: Array<Node> = [];
    constructor(prefab: Node | Prefab) {
        this.prefab = prefab;
    }
    public Get() {
        if (this.pool.length > 0 && this.checkIsIdleGo(this.pool)) {
            let go: Node = this.getIdleGo(this.pool);
            go.active = true;
            go.setPosition(Vec3.ZERO);
            return go;
        } else {
            // LogManager.log("池子内预制不够,创建元素");
            let go: any = instantiate(this.prefab);
            go.active = true;
            this.pool.push(go);
            return go;
        }
    }
    public Save(go: Node, delay: number = 0, callback?) {
        if (delay == 0) {
            this.runSaveVoid(go, callback);
        } else {
            let set1 = setTimeout(() => {
                clearTimeout(set1);
                this.runSaveVoid(go, callback);
            }, delay);
        }
    }
    public SaveAll() {
        for (let i = this.pool.length - 1; i >= 0; i--) {
            this.pool[i].active = false;
            this.pool[i].parent = null;
        }
    }
    public Clean() {
        this.pool = [];
    }
    private runSaveVoid(go, callback) {
        go.getComponent(Animation) && go.getComponent(Animation).stop();
        go.active = false;
        go.parent = null;
        callback && callback();
    }
    private checkIsIdleGo(pool) {
        for (let i = 0; i < pool.length; i++) {
            if (!pool[i].active) {
                return true;
            }
        }
        return false;
    }
    private getIdleGo(pool) {
        let index = pool.findIndex((item) => {
            return !item.active;
        });
        if (index != -1) {
            return pool[index];
        }
    }
}

ObjectPool中的方法是跟PoolManager一一对应,其作用是对节点的状态执行更新

创建池对象数据结果的类

Dictionary 是一个泛型类,主要用于实现键值对存储的数据结构,类似于 Map。

export class Dictionary<T> {
    dataStore = {};
    add(key: string, value: T) {
        this.dataStore[key] = value;
    }
    remove(key: string) {
        if (this.dataStore[key]) delete this.dataStore[key];
    }
    getValue(key: string) {
        if (this.dataStore[key]) {
            return this.dataStore[key];
        } else {
            // warn("key Not Found", key);
            return null;
        }
    }
    containsKey(key: string) {
        if (this.dataStore.hasOwnProperty(key)) return true;
        return false;
    }
    showAll() {
        for (const key in this.dataStore) {
            if (this.dataStore.hasOwnProperty(key)) {
                log(key, "-->", this.dataStore[key]);
            }
        }
    }
    clear() {
        this.dataStore = {};
    }
    count() {
        let num = 0;
        for (const key in this.dataStore) {
            num++;
        }
        return num;
    }
}

对象池使用

PoolManager.CreatePool("pool", Node); // 创建对象池
let item = PoolManager.Get("pool"); // 拿出来一个节点使用
item.setParent(parentNode); // 挂载到目标父节点下
PoolManager.Save("pool", item); // 将节点状态变成不活跃