/** * Prefab对象池类 * 1. 占用并复用资源,使用Mgr.ResMgr加载资源并标记为资源池占用 * 2. Prefab对象管理、缓存、创建,每个Prefab资源对应一个池子 * 3. 针对每个Prefab对象池的水位控制 * 4. freePrefab 里面检测node是否有效,无效的node报错提示,_createCount-- * * @format */ import {BaseUI} from '../ui/BaseUI' import {Log} from '../utils/LogUtils' import {Data} from '../GameControl' export interface IPrefabPool { baseUI: BaseUI prefabReset(): void } export class PrefabPool { private _createCount: number = 0 private _waterMark: number = 10 private readonly _url: string private readonly _res: cc.Prefab = null private _nodes: cc.Node[] = [] public constructor(url: string, prefab: cc.Prefab) { this._url = url this._res = prefab } /** * 获取url */ public getUrl(): string { return this._url } /** * 获取prefab * @param url prefab的url */ public getPrefab(): cc.Node { if (this._nodes.length > 0) { const node = this._nodes.pop() if (cc.isValid(node)) { node.active = true return node } node.destroy() this._createCount++ return cc.instantiate(this._res) } this._createCount++ return cc.instantiate(this._res) } /** * 回收prefab * @param url prefab的url * @param node */ public freePrefab(node: cc.Node) { if (!(node && cc.isValid(node))) { cc.error('[ERROR] PrefabPool: freePrefab: isValid node') this._createCount-- return } if (this._waterMark < this._nodes.length) { this._createCount-- Log.warn('PrefabPoolManager freePrefab: waterMark is below') node.destroy() } else { node.stopAllActions() node.parent = null node.position = cc.Vec3.ZERO node.scale = 1 const components = node['_components'] components.forEach(value => { if (value['prefabReset']) { value.prefabReset() } }) this._nodes.push(node) } } /** * 设置回收池缓存个数 * @param waterMark 缓存个数 */ public setWaterMark(waterMark: number) { if (waterMark > this._waterMark) { this._waterMark = waterMark } } /** * 池子里的prefab是否都没有使用 */ public isUnuse() { if (this._nodes.length > this._createCount) { cc.error('PrefabPool: _nodes.length > _createCount') } return this._nodes.length == this._createCount } /** * 清空prefab */ public destroy() { // 清空节点、回收资源 for (const node of this._nodes) { node.destroy() } this._createCount -= this._nodes.length this._nodes.length = 0 cc.assetManager.releaseAsset(this._res) } // 只清理池子不回收 public clearPool() { for (const node of this._nodes) { node.destroy() } this._createCount -= this._nodes.length this._nodes.length = 0 } } export class PrefabPoolManager { private _pools: Map = new Map() // Prefab url loadRes时待处理的callback private finishCallbackMap: Map = new Map() public initPrefabPoolByPrefab(url: string, prefab: cc.Prefab, waterMark: number = 64) { if (!this._pools.has(url)) { const pool = new PrefabPool(url, prefab) pool.setWaterMark(waterMark) this._pools.set(url, pool) } } //初始化节点对 public initPoolNode(poolKey: string, prefab: cc.Prefab, waterMark: number = 64) { let pool = Data.main.itemsPoolMap.get(poolKey) if (!pool) { pool = new cc.NodePool() } for (let i = pool.size(); i < waterMark; ++i) { let obj = cc.instantiate(prefab) pool.put(obj) } Data.main.itemsPoolMap.set(poolKey, pool) } /** * 获取prefab池 * @param url prefab的url */ public getPool(url: string): PrefabPool { return this._pools.get(url) } /** * 判断是不是有prefab池 * @param url prefab的url */ public hasPool(url: string) { return this._pools.has(url) } /** * 销毁prefab池 * @param url prefab的url */ public destroyPool(url: string) { if (this._pools.has(url)) { this._pools.get(url).destroy() this._pools.delete(url) } } /** * 初始化预设池返回实例化节点,并返回Promise */ public getNodeAsync( url: string, bundle: cc.AssetManager.Bundle = cc.resources, waterMark: number = 64, ): Promise { return new Promise((resolve, reject) => { if (this._pools.has(url)) { let pool = this._pools.get(url) resolve(pool.getPrefab()) } else { bundle.load(url, cc.Prefab, (error, res: cc.Prefab) => { let pool: PrefabPool = null if (!error) { pool = new PrefabPool(url, res) pool.setWaterMark(waterMark) this._pools.set(url, pool) resolve(pool.getPrefab()) } else { reject(null) } }) } }) } public reset() { this.finishCallbackMap.clear() this._pools.forEach(value => { this.destroyPool(value.getUrl()) }) } }