2024-06-07 00:08:39 -07:00
|
|
|
import { _decorator, Component, director, instantiate, Node, Prefab } from 'cc';
|
2024-03-06 07:10:31 -08:00
|
|
|
import IPoolable from './IPoolable';
|
2024-03-06 01:28:01 -08:00
|
|
|
|
2024-03-06 03:09:17 -08:00
|
|
|
export default class ObjectPool {
|
2024-03-11 04:12:22 -07:00
|
|
|
private _inactive: Node[] = [];
|
2024-03-06 01:28:01 -08:00
|
|
|
private _actives: Node[] = [];
|
|
|
|
private _prefab: Prefab;
|
|
|
|
private _expandable;
|
2024-06-07 00:08:39 -07:00
|
|
|
private _poolHandlerComp: (new () => any) | string;
|
2024-03-06 01:28:01 -08:00
|
|
|
|
2024-06-07 00:08:39 -07:00
|
|
|
public get listActive() {
|
2024-04-01 19:26:53 -07:00
|
|
|
return [...this._actives];
|
|
|
|
}
|
|
|
|
|
2024-06-07 00:08:39 -07:00
|
|
|
public get listInactive() {
|
2024-04-01 19:26:53 -07:00
|
|
|
return [...this._inactive];
|
|
|
|
}
|
|
|
|
|
|
|
|
public get all() {
|
2024-03-11 04:12:22 -07:00
|
|
|
return [...this._actives, ...this._inactive];
|
|
|
|
}
|
|
|
|
|
2024-03-06 01:28:01 -08:00
|
|
|
public get countInactive() {
|
2024-03-11 04:12:22 -07:00
|
|
|
return this._inactive.length;
|
2024-03-06 01:28:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
public get countActive() {
|
|
|
|
return this._actives.length;
|
|
|
|
}
|
|
|
|
|
|
|
|
public get countAll() {
|
|
|
|
return this.countInactive + this.countActive;
|
|
|
|
}
|
|
|
|
|
2024-06-07 00:08:39 -07:00
|
|
|
constructor(
|
|
|
|
prefab?: Prefab,
|
|
|
|
size?: number,
|
|
|
|
expandable: boolean = true,
|
|
|
|
poolHandlerComp?: (new () => any) | string,
|
|
|
|
) {
|
2024-03-28 20:35:44 -07:00
|
|
|
if (!!!prefab) {
|
|
|
|
console.error('prefab cant be null or undefine');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-03-06 01:28:01 -08:00
|
|
|
this._prefab = prefab;
|
2024-03-06 07:10:31 -08:00
|
|
|
this._expandable = expandable;
|
|
|
|
this._poolHandlerComp = poolHandlerComp;
|
2024-03-06 01:28:01 -08:00
|
|
|
for (let i = 0; i < size; ++i) {
|
|
|
|
let obj = instantiate(this._prefab); // create node instance
|
2024-03-06 07:10:31 -08:00
|
|
|
obj.removeFromParent();
|
2024-03-11 04:12:22 -07:00
|
|
|
this._inactive.push(obj);
|
2024-06-07 00:08:39 -07:00
|
|
|
ObjectPool._poolLookUp.set(obj, this);
|
2024-03-06 01:28:01 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-07 09:45:13 -08:00
|
|
|
//#region Static
|
2024-06-07 00:08:39 -07:00
|
|
|
private static _poolLookUp: Map<Node, ObjectPool> = new Map();
|
|
|
|
public static release(obj: Node): boolean {
|
|
|
|
return ObjectPool._poolLookUp.get(obj)?.release(obj);
|
2024-03-07 09:45:13 -08:00
|
|
|
}
|
|
|
|
//#endregion
|
|
|
|
|
2024-03-06 03:09:17 -08:00
|
|
|
public get(parent?: Node): Node;
|
2024-04-03 02:43:18 -07:00
|
|
|
public get<T extends Component>(classConstructor: new () => T): T;
|
|
|
|
public get<T extends Component>(classConstructor: new () => T, parent: Node): T;
|
|
|
|
public get<T extends Component>(a?: (new () => T) | Node, b?: Node): T | Node {
|
2024-03-28 20:35:44 -07:00
|
|
|
if (!!!this._prefab) {
|
|
|
|
console.error('prefab cant be null or undefine');
|
|
|
|
return;
|
|
|
|
}
|
2024-04-03 02:43:18 -07:00
|
|
|
|
|
|
|
let parent: Node;
|
|
|
|
let classConstructor: new () => T;
|
|
|
|
if (a instanceof Node) {
|
|
|
|
parent = a || director.getScene();
|
|
|
|
} else {
|
|
|
|
parent = b || director.getScene();
|
|
|
|
classConstructor = a;
|
|
|
|
}
|
|
|
|
|
2024-03-06 01:28:01 -08:00
|
|
|
let obj: Node = null;
|
2024-03-11 04:12:22 -07:00
|
|
|
if (this._inactive.length > 0) {
|
2024-03-06 07:10:31 -08:00
|
|
|
// Pop the last object in pool
|
2024-03-11 04:12:22 -07:00
|
|
|
obj = this._inactive.pop();
|
2024-03-06 01:28:01 -08:00
|
|
|
} else if (this._expandable) {
|
|
|
|
// if not enough node in the pool, we call cc.instantiate to create node
|
|
|
|
obj = instantiate(this._prefab);
|
2024-06-07 00:08:39 -07:00
|
|
|
ObjectPool._poolLookUp.set(obj, this);
|
2024-03-06 01:28:01 -08:00
|
|
|
} else {
|
2024-03-06 03:09:17 -08:00
|
|
|
obj = this._actives.shift();
|
2024-03-28 20:35:44 -07:00
|
|
|
obj.removeFromParent();
|
2024-03-06 01:28:01 -08:00
|
|
|
}
|
|
|
|
|
2024-04-03 02:43:18 -07:00
|
|
|
obj.setParent(parent);
|
2024-03-06 07:10:31 -08:00
|
|
|
this._actives.push(obj);
|
|
|
|
// Invoke pool handler
|
2024-06-07 00:08:39 -07:00
|
|
|
let handler: Component = null;
|
|
|
|
if (typeof this._poolHandlerComp == 'string') {
|
|
|
|
handler = this._poolHandlerComp ? obj.getComponent(this._poolHandlerComp) : null;
|
|
|
|
} else {
|
|
|
|
handler = this._poolHandlerComp ? obj.getComponent(this._poolHandlerComp) : null;
|
|
|
|
}
|
2024-03-06 07:10:31 -08:00
|
|
|
if (handler) {
|
2024-03-10 03:12:55 -07:00
|
|
|
(handler as unknown as IPoolable)?.onGet();
|
2024-03-06 07:10:31 -08:00
|
|
|
}
|
2024-03-06 03:09:17 -08:00
|
|
|
if (classConstructor) {
|
2024-06-07 00:08:39 -07:00
|
|
|
return obj.getComponent(classConstructor);
|
2024-03-06 03:09:17 -08:00
|
|
|
}
|
|
|
|
return obj;
|
2024-03-06 01:28:01 -08:00
|
|
|
}
|
|
|
|
|
2024-06-07 00:08:39 -07:00
|
|
|
public release(obj: Node): boolean;
|
|
|
|
public release<T extends Component>(obj: T): boolean;
|
|
|
|
public release<T extends Component>(obj: T | Node): boolean {
|
2024-03-06 07:10:31 -08:00
|
|
|
let node = obj instanceof Node ? obj : obj.node;
|
|
|
|
const index = this._actives.indexOf(node);
|
2024-03-11 04:12:22 -07:00
|
|
|
|
2024-03-06 07:10:31 -08:00
|
|
|
//check obj is belongs to pool
|
2024-06-07 00:08:39 -07:00
|
|
|
if (index === -1) return false;
|
2024-03-06 07:10:31 -08:00
|
|
|
this._actives.splice(index, 1);
|
2024-03-11 04:12:22 -07:00
|
|
|
this._inactive.push(node);
|
2024-03-06 07:10:31 -08:00
|
|
|
// Invoke pool handler
|
|
|
|
|
2024-06-07 00:08:39 -07:00
|
|
|
let handler: Component = null;
|
|
|
|
if (typeof this._poolHandlerComp == 'string') {
|
|
|
|
handler = this._poolHandlerComp ? node.getComponent(this._poolHandlerComp) : null;
|
|
|
|
} else {
|
|
|
|
handler = this._poolHandlerComp ? node.getComponent(this._poolHandlerComp) : null;
|
|
|
|
}
|
2024-03-06 07:10:31 -08:00
|
|
|
if (handler) {
|
2024-03-10 03:12:55 -07:00
|
|
|
(handler as unknown as IPoolable)?.onRelease();
|
2024-03-06 03:09:17 -08:00
|
|
|
}
|
2024-03-06 07:10:31 -08:00
|
|
|
// Remove from parent, but don't cleanup
|
|
|
|
node.removeFromParent();
|
2024-06-07 00:08:39 -07:00
|
|
|
return true;
|
2024-03-06 01:28:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
public clear() {
|
2024-03-11 04:12:22 -07:00
|
|
|
this.all.forEach((obj) => obj.destroy());
|
|
|
|
this._inactive = [];
|
2024-03-06 01:28:01 -08:00
|
|
|
this._actives = [];
|
2024-06-07 00:08:39 -07:00
|
|
|
ObjectPool._poolLookUp.clear();
|
2024-03-06 01:28:01 -08:00
|
|
|
}
|
2024-03-11 04:12:22 -07:00
|
|
|
|
|
|
|
public releaseAll() {
|
|
|
|
this.all.forEach((obj) => this.release(obj));
|
|
|
|
}
|
2024-03-06 01:28:01 -08:00
|
|
|
}
|