PrefabPoolManager.ts 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. /**
  2. * Prefab对象池类
  3. * 1. 占用并复用资源,使用Mgr.ResMgr加载资源并标记为资源池占用
  4. * 2. Prefab对象管理、缓存、创建,每个Prefab资源对应一个池子
  5. * 3. 针对每个Prefab对象池的水位控制
  6. * 4. freePrefab 里面检测node是否有效,无效的node报错提示,_createCount--
  7. *
  8. * @format
  9. */
  10. import {BaseUI} from '../ui/BaseUI'
  11. import {Log} from '../utils/LogUtils'
  12. import {Data} from '../GameControl'
  13. export interface IPrefabPool {
  14. baseUI: BaseUI
  15. prefabReset(): void
  16. }
  17. export class PrefabPool {
  18. private _createCount: number = 0
  19. private _waterMark: number = 10
  20. private readonly _url: string
  21. private readonly _res: cc.Prefab = null
  22. private _nodes: cc.Node[] = []
  23. public constructor(url: string, prefab: cc.Prefab) {
  24. this._url = url
  25. this._res = prefab
  26. }
  27. /**
  28. * 获取url
  29. */
  30. public getUrl(): string {
  31. return this._url
  32. }
  33. /**
  34. * 获取prefab
  35. * @param url prefab的url
  36. */
  37. public getPrefab(): cc.Node {
  38. if (this._nodes.length > 0) {
  39. const node = this._nodes.pop()
  40. if (cc.isValid(node)) {
  41. node.active = true
  42. return node
  43. }
  44. node.destroy()
  45. this._createCount++
  46. return cc.instantiate(this._res)
  47. }
  48. this._createCount++
  49. return cc.instantiate(this._res)
  50. }
  51. /**
  52. * 回收prefab
  53. * @param url prefab的url
  54. * @param node
  55. */
  56. public freePrefab(node: cc.Node) {
  57. if (!(node && cc.isValid(node))) {
  58. cc.error('[ERROR] PrefabPool: freePrefab: isValid node')
  59. this._createCount--
  60. return
  61. }
  62. if (this._waterMark < this._nodes.length) {
  63. this._createCount--
  64. Log.warn('PrefabPoolManager freePrefab: waterMark is below')
  65. node.destroy()
  66. } else {
  67. node.stopAllActions()
  68. node.parent = null
  69. node.position = cc.Vec3.ZERO
  70. node.scale = 1
  71. const components = node['_components']
  72. components.forEach(value => {
  73. if (value['prefabReset']) {
  74. value.prefabReset()
  75. }
  76. })
  77. this._nodes.push(node)
  78. }
  79. }
  80. /**
  81. * 设置回收池缓存个数
  82. * @param waterMark 缓存个数
  83. */
  84. public setWaterMark(waterMark: number) {
  85. if (waterMark > this._waterMark) {
  86. this._waterMark = waterMark
  87. }
  88. }
  89. /**
  90. * 池子里的prefab是否都没有使用
  91. */
  92. public isUnuse() {
  93. if (this._nodes.length > this._createCount) {
  94. cc.error('PrefabPool: _nodes.length > _createCount')
  95. }
  96. return this._nodes.length == this._createCount
  97. }
  98. /**
  99. * 清空prefab
  100. */
  101. public destroy() {
  102. // 清空节点、回收资源
  103. for (const node of this._nodes) {
  104. node.destroy()
  105. }
  106. this._createCount -= this._nodes.length
  107. this._nodes.length = 0
  108. cc.assetManager.releaseAsset(this._res)
  109. }
  110. // 只清理池子不回收
  111. public clearPool() {
  112. for (const node of this._nodes) {
  113. node.destroy()
  114. }
  115. this._createCount -= this._nodes.length
  116. this._nodes.length = 0
  117. }
  118. }
  119. export class PrefabPoolManager {
  120. private _pools: Map<string, PrefabPool> = new Map<string, PrefabPool>()
  121. // Prefab url loadRes时待处理的callback
  122. private finishCallbackMap: Map<string, any[]> = new Map<string, any[]>()
  123. public initPrefabPoolByPrefab(url: string, prefab: cc.Prefab, waterMark: number = 64) {
  124. if (!this._pools.has(url)) {
  125. const pool = new PrefabPool(url, prefab)
  126. pool.setWaterMark(waterMark)
  127. this._pools.set(url, pool)
  128. }
  129. }
  130. //初始化节点对
  131. public initPoolNode(poolKey: string, prefab: cc.Prefab, waterMark: number = 64) {
  132. let pool = Data.main.itemsPoolMap.get(poolKey)
  133. if (!pool) {
  134. pool = new cc.NodePool()
  135. }
  136. for (let i = pool.size(); i < waterMark; ++i) {
  137. let obj = cc.instantiate(prefab)
  138. pool.put(obj)
  139. }
  140. Data.main.itemsPoolMap.set(poolKey, pool)
  141. }
  142. /**
  143. * 获取prefab池
  144. * @param url prefab的url
  145. */
  146. public getPool(url: string): PrefabPool {
  147. return this._pools.get(url)
  148. }
  149. /**
  150. * 判断是不是有prefab池
  151. * @param url prefab的url
  152. */
  153. public hasPool(url: string) {
  154. return this._pools.has(url)
  155. }
  156. /**
  157. * 销毁prefab池
  158. * @param url prefab的url
  159. */
  160. public destroyPool(url: string) {
  161. if (this._pools.has(url)) {
  162. this._pools.get(url).destroy()
  163. this._pools.delete(url)
  164. }
  165. }
  166. /**
  167. * 初始化预设池返回实例化节点,并返回Promise
  168. */
  169. public getNodeAsync(
  170. url: string,
  171. bundle: cc.AssetManager.Bundle = cc.resources,
  172. waterMark: number = 64,
  173. ): Promise<cc.Node> {
  174. return new Promise((resolve, reject) => {
  175. if (this._pools.has(url)) {
  176. let pool = this._pools.get(url)
  177. resolve(pool.getPrefab())
  178. } else {
  179. bundle.load(url, cc.Prefab, (error, res: cc.Prefab) => {
  180. let pool: PrefabPool = null
  181. if (!error) {
  182. pool = new PrefabPool(url, res)
  183. pool.setWaterMark(waterMark)
  184. this._pools.set(url, pool)
  185. resolve(pool.getPrefab())
  186. } else {
  187. reject(null)
  188. }
  189. })
  190. }
  191. })
  192. }
  193. public reset() {
  194. this.finishCallbackMap.clear()
  195. this._pools.forEach(value => {
  196. this.destroyPool(value.getUrl())
  197. })
  198. }
  199. }