import { Component, Node, Prefab, director, instantiate } from 'cc'; import IPoolable from './IPoolable'; export default class ObjectPool { private _inactives: Node[] = []; private _actives: Node[] = []; private _prefab: Prefab; private _expandable; private _poolHandlerComp: new () => any; public get countInactive() { return this._inactives.length; } public get countActive() { return this._actives.length; } public get countAll() { return this.countInactive + this.countActive; } constructor(prefab: Prefab, size: number, expandable = true, poolHandlerComp?: new () => any | string) { this._prefab = prefab; this._expandable = expandable; this._poolHandlerComp = poolHandlerComp; for (let i = 0; i < size; ++i) { let obj = instantiate(this._prefab); // create node instance obj.removeFromParent(); this._inactives.push(obj); ObjectPool._poolLookUp[obj.uuid] = this; } } //#region Static private static _poolLookUp: { [key: string]: ObjectPool } = {}; public static release(obj: Node) { ObjectPool._poolLookUp[obj.uuid].release(obj); } //#endregion public get(parent?: Node): Node; public get(parent?: Node, classConstructor?: new () => T): T; public get(parent?: Node, classConstructor?: new () => T): T | Node { let obj: Node = null; let p = parent || director.getScene(); if (this._inactives.length > 0) { // Pop the last object in pool obj = this._inactives.pop(); } else if (this._expandable) { // if not enough node in the pool, we call cc.instantiate to create node obj = instantiate(this._prefab); ObjectPool._poolLookUp[obj.uuid] = this; } else { obj = this._actives.shift(); } obj.setParent(p); this._actives.push(obj); // Invoke pool handler const handler = this._poolHandlerComp ? obj.getComponent(this._poolHandlerComp) : null; if (handler) { (handler as unknown as IPoolable)?.onGet(); } if (classConstructor) { return handler == classConstructor ? handler : obj.getComponent(classConstructor); } return obj; } public release(obj: Node): void; public release(obj: T): void; public release(obj: T | Node): void { let node = obj instanceof Node ? obj : obj.node; const index = this._actives.indexOf(node); //check obj is belongs to pool if (index === -1) return; this._actives.splice(index, 1); this._inactives.push(node); // Invoke pool handler const handler = this._poolHandlerComp ? node.getComponent(this._poolHandlerComp) : null; if (handler) { (handler as unknown as IPoolable)?.onRelease(); } // Remove from parent, but don't cleanup node.removeFromParent(); } public clear() { this._inactives.forEach((obj) => obj.destroy()); this._inactives = []; this._actives = []; Object.keys(ObjectPool._poolLookUp).forEach((key) => { if (ObjectPool._poolLookUp[key] === this) { delete ObjectPool._poolLookUp[key]; } }); } }