官方提供的NodePool不太好用 想要使用get获取对象 必须要预先创建。但有的时候预先并不清楚需要创建多少个,创建多了少了都不太好,而且在用NodePool的地方都要自己封装一个创建预制体的方法
所以这里封装了一个Pool 使用的时候不需要关心数量 如果池中有?->直接用 没有?->创建
并且被创建的对象绝对不会有多余或不够的情况
比如第一次发射100发子弹 创建100预制体 此时池中就有100可用的缓存
回收之后 第二次如果发射150个 则会自动创建超出的50个
import { Component, Prefab, Node, director, Constructor, instantiate } from "cc";
type PoolTotalCallback<T> = (item: T | Node, data: any, index: number) => void
type PoolPushCallback<T> = (item: T | Node, index: number) => void
/** 对象池管理类 */
export class Pool<T extends Component = Component> {
private prefab: Prefab | Node
private parent: Node
private component: Constructor<T>
private gener!: Generator
private _caches: any[]
private _uses: any[]
get caches() { return Object.assign([], this._caches) }
get uses() { return Object.assign([], this._uses) }
constructor(prefab: Prefab | Node, parent: Node, component?: Constructor<T>) {
this.prefab = prefab
this.parent = parent
this.component = component
this._caches = []
this._uses = []
}
/**
* 从对象池中创建一组对象
*/
public total(arrayOrNumber: any[] | number, done: PoolTotalCallback<T>, duration: number = 10): Promise<void> {
return new Promise(async (resolve, reject) => {
if (arrayOrNumber == undefined || arrayOrNumber == null || typeof arrayOrNumber == "number" && isNaN(arrayOrNumber)) return resolve()
this.gener?.return("")
let length = arrayOrNumber instanceof Array ? arrayOrNumber.length : arrayOrNumber
let data = arrayOrNumber instanceof Array ? arrayOrNumber : null
this.gener = this.getGenerator(length, this.task.bind(this), data, done)
await this.exeGenerator(this.gener, duration)
this.surplus(length)
resolve()
})
}
/**
* 添加一个对象
*/
push(done: PoolPushCallback<T>): void {
let node = this.getNode()
done(node, this._uses.length - 1)
}
/**
* 弹出一个对象
* @param node 要弹出的对象
*/
pop(node: Node | T): boolean {
if (!node) return
let curre = node instanceof Node ? node : node.node
let index = this._uses.findIndex(item => {
if (item instanceof Node) return item.uuid == curre.uuid
return item.node.uuid == curre.uuid
})
if (index == -1) return false
let obj = this._uses.splice(index, 1)[0]
obj instanceof Node ? obj.removeFromParent() : obj.node.removeFromParent()
this._caches.push(obj)
return true
}
/**
* 回收所有对象到对象池
*/
recycle(): void {
try {
while (this._uses.length > 0) {
let obj = this._uses.pop()
obj instanceof Node ? obj.removeFromParent() : obj.node.removeFromParent()
this._caches.push(obj)
}
} catch (error) {
console.error(error)
}
}
/**
* 清理对象池
*/
clear() {
let list = [...this._uses, ...this._caches]
for (let i = 0; i < list.length; i++) {
const obj = list[i];
obj instanceof Node ? obj.destroy() : obj.node.destroy()
}
this._caches = []
this._uses = []
}
private task(index: number, array: any[] | null, done: PoolTotalCallback<T>) {
let data = array?.[index] || index
let node = this.getNode()
done(node, data, index)
}
private surplus(length: number) {
try {
while (this._uses.length - length) {
let obj = this._uses.pop()
if (obj instanceof Node) {
obj.removeFromParent()
} else {
obj.node.removeFromParent()
}
this._caches.push(obj)
}
} catch (error) {
console.error(error)
}
}
private getNode(): T | Node {
if (this._caches.length == 0) {
let obj = instantiate(this.prefab) as Node
let item = obj.getComponent(this.component) || obj
this._caches.push(item)
}
let node = this._caches.pop()
if (node instanceof Node) {
node.parent = this.parent
} else {
node.node.parent = this.parent
}
this._uses.push(node)
return node
}
private * getGenerator(length: number, callback: Function, ...params: any): Generator {
for (let i = 0; i < length; i++) {
yield callback(i, ...params)
}
}
private exeGenerator(generator: Generator, duration: number) {
return new Promise((resolve, reject) => {
let gen = generator
let execute = () => {
let startTime = new Date().getTime()
for (let iter = gen.next(); ; iter = gen.next()) {
if (iter == null || iter.done) {
resolve(null)
return
}
if (new Date().getTime() - startTime > duration) {
setTimeout(() => {
execute()
}, director.getDeltaTime() * 1000)
return
}
}
}
execute()
})
}
}
使用方法
this.pool = new Pool(this.prefab, this.content, RootItem)
// 你的数据
var dataArray = [1, 2, 3, 4, 5, 6, 7, 8, 9]
// 批量创建 方法一 直接传入数据数组
await this.pool.total(dataArray, (item: RootItem, data: any, index: number) => {
// data = dataArray[index]
item.show(data)
})
// 批量创建 方法二 传入数量
await this.pool.total(dataArray.length, (item: RootItem, data: any, index: number) => {
// data = null
item.show(dataArray[index])
})
// 数据发生变化时重新调用total
dataArray = [1,2,3]
await this.pool.total(dataArray, (item: RootItem, data: any, index: number) => {
// data = dataArray[index]
item.show(data)
})
// 再添加一个对象
this.pool.push((item: RootItem, index: number) => {
item.show(index)
})
// 回收一个到对象池
let node = this.pool.uses[0] //找到要回收的那个对象
this.pool.pop(node)
// 回收所有
this.pool.recycle()
// 清理对象池 删除对象
this.pool.clear()