--region *.lua --Date --此文件由[BabeLua]插件自动生成 PoolManager = quick_class("PoolManager") PoolManager.AssetType = { MediaUI = 1, MediaBg = 2, Texture = 3, GameObject = 4, Other = 5, } PoolManager.mClearTime_Idle = 100 PoolManager.mClearTime_Busy = 10 PoolManager.mMaxPoolSize = 30 PoolManager.enableRecycle = true function PoolManager:ctor() self:init() end function PoolManager:Update() self.mFrameTimer = self.mFrameTimer + 1 if PoolManager.enableRecycle and self.mFrameTimer % self.mClearTime == 0 then self:RemoveEarliesItem() end end function PoolManager:init() self.mPoolTable = {} self.mLiveTable = {} self.mPoolNode = GameObject("PoolNode") GameObject.DontDestroyOnLoad(self.mPoolNode) self.mPoolTrans = self.mPoolNode.transform self.mPoolNode:SetActive(false) self.mFrameTimer = 0 --清理间隔 self.mClearTime = PoolManager.mClearTime_Idle self.mPoolSize = PoolManager.mMaxPoolSize LateUpdateBeat:Add(self.Update,self) end function PoolManager:onDestroy() for outIndex,gameData in pairs(self.mPoolTable) do if gameData.resList then for _,data in ipairs(gameData.resList) do if gameData.useInstantiate then GameObject.DestroyImmediate(data) end end gameData.resList = {} end resMgr:UnLoadAsset(outIndex) gameData.refCount = 0 end self.mPoolTable = {} GameObject.DestroyImmediate(self.mPoolNode) end function PoolManager:SetRecycleState( state) PoolManager.enableRecycle = state end --[[ 预加载资源 ]] function PoolManager:PreLoadAsset(resName,num, assetType, func) local tempTable = self.mPoolTable[resName] if tempTable == nil then tempTable = {} tempTable.resList = {} tempTable.useFrame = 0 tempTable.refCount = 0 tempTable.useInstantiate = false self.mPoolTable[resName] = tempTable end resMgr:LoadAssetAsync(resName,function(name,Obj) if Obj ~= nil then local index = 1 local resObj = nil if assetType == PoolManager.AssetType.GameObject then while index <= num do resObj = GameObject.Instantiate(Obj) resObj:SetActive(true) resObj.transform:SetParent(self.mPoolTrans) tempTable.useInstantiate = true table.insert(tempTable.resList,resObj) index = index + 1 tempTable.refCount = tempTable.refCount + 1 end else table.insert(tempTable.resList,Obj) tempTable.refCount = tempTable.refCount + 1 end tempTable.activeTime = self.mFrameTimer end if func then func() end end) end function PoolManager:LoadAsset(resName, assetType) local tempTable = self.mPoolTable[resName] if tempTable == nil then tempTable = {} tempTable.resList = {} tempTable.preLoadCount = 0 tempTable.usedFrame = 0 tempTable.useInstantiate = false tempTable.refCount = 0 self.mPoolTable[resName] = tempTable end local resObj = nil if #tempTable.resList > 0 then resObj = tempTable.resList[#tempTable.resList] --只有GameObject需要被回收,其他类型的资源只用缓存 if assetType == PoolManager.AssetType.GameObject then table.remove(tempTable.resList,#tempTable.resList) end else local _obj = resMgr:LoadAsset(resName) if _obj == nil then Log("resource is nil! error:"..resName) resMgr:UnLoadAsset(resName) return nil end if assetType == PoolManager.AssetType.GameObject then resObj = GameObject.Instantiate(_obj) resObj:SetActive(true) tempTable.useInstantiate = true else resObj = _obj --缓存非GameObject资源 table.insert(tempTable.resList,resObj) end end tempTable.refCount = tempTable.refCount + 1 tempTable.activeTime = self.mFrameTimer return resObj end function PoolManager:LoadAssetAsync(resName, assetType, callBack) local tempTable = self.mPoolTable[resName] if tempTable == nil then tempTable = {} tempTable.resList = {} tempTable.preLoadCount = 0 tempTable.usedFrame = 0 tempTable.useInstantiate = false tempTable.refCount = 0 self.mPoolTable[resName] = tempTable end resMgr:LoadAssetAsync(resName, function(name,Obj) if Obj ~= nil then local resObj = nil if assetType == PoolManager.AssetType.GameObject then resObj = GameObject.Instantiate(Obj) resObj:SetActive(true) tempTable.useInstantiate = true else resObj = Obj --缓存非GameObject资源 table.insert(tempTable.resList,resObj) end tempTable.refCount = tempTable.refCount + 1 tempTable.activeTime = self.mFrameTimer end if callBack then callBack(Obj) end end) end --[[ resName res:real res Object ]] function PoolManager:UnLoadAsset(resName,res, assetType) local pool = self.mPoolTable[resName] if pool == nil or pool.resList == nil then return end --if assetType ~= PoolManager.AssetType.Texture -- and assetType ~= PoolManager.AssetType.MediaBg -- and assetType ~= PoolManager.AssetType.MediaUI --then if assetType == PoolManager.AssetType.GameObject and res and tostring(res) ~= "null" then res.transform:SetParent(self.mPoolTrans) if #pool.resList <= 5 then table.insert(pool.resList,res) else GameObject.DestroyImmediate(res) end end pool.refCount = pool.refCount -1 end function PoolManager:RemoveEarliesItem() local poolCount = table.nums(self.mPoolTable) if poolCount < self.mPoolSize then self.mClearTime = PoolManager.mClearTime_Idle return end self.mClearTime = PoolManager.mClearTime_Busy --logWarn("Pool Update --" .. poolCount .. " -- " .. self.mFrameTimer) local earliestTime = 2147483647 local removedResName = nil local removedIndex = -1 local index = 1 local pool = nil for k,v in pairs(self.mPoolTable) do if v.refCount < 1 then if v.activeTime ~= nil and v.activeTime < earliestTime then earliestTime = v.activeTime removedResName = k removedIndex = index pool = v end end index = index +1 end if removedResName == nil or pool == nil then if self.mPoolSize < PoolManager.mMaxPoolSize then self.mPoolSize = PoolManager.mMaxPoolSize end return end if pool.useInstantiate then if pool.useInstantiate and pool.resList ~= nil and table.nums( pool.resList ) > 0 then for _,data in ipairs(pool.resList) do if data ~= nil then GameObject.DestroyImmediate(data) end end end pool.resList = nil end --table.remove(self.mPoolTable) self.mPoolTable[removedResName] = nil resMgr:UnLoadAsset(removedResName) --logWarn("Remove Pool item:" .. removedResName) --logWarn("Objects in Pool!!!" .. table.nums(self.mPoolTable)) end function PoolManager:ClearPool() self.mPoolSize = 0 self.mClearTime = 1 end function PoolManager:LoadLive(liveName, parent, scaleV3, posV3, onClear) local testLive = self:LoadAsset(liveName, PoolManager.AssetType.GameObject) if testLive then testLive.transform:SetParent(parent) testLive.transform.localScale = scaleV3 testLive.transform.localPosition = posV3 testLive.name = liveName testLive:SetActive(true) local SkeletonGraphic = testLive:GetComponent("SkeletonGraphic") SkeletonGraphic.color = Color.New(1,1,1,1) end if not self.mLiveTable[liveName] then self.mLiveTable[liveName] = {} end table.insert(self.mLiveTable[liveName], {live = testLive, call = onClear}) return testLive end --设置清理回调,当live对象被回收到对象池中,触发清理回调 function PoolManager:SetLiveClearCall(resName, res, onClear) if self.mLiveTable[resName] then local item for i=1, #self.mLiveTable[resName] do item = self.mLiveTable[resName][i] if item.live == res then item.call = onClear break end end end end function PoolManager:UnLoadLive(resName, res) self:UnLoadAsset(resName, res, PoolManager.AssetType.GameObject) if self.mLiveTable[resName] then local item for i=1, #self.mLiveTable[resName] do item = self.mLiveTable[resName][i] if item.live == res then if item.call then item.call() end table.remove(self.mLiveTable[resName], i) break end end end end --卸载对应游戏内存池的资源 --[[ resName: 可选 ]] function PoolManager:UnLoadGameAsset(resName) for outIndex, gameData in pairs(self.mPoolTable) do local tempIndex = 1 for index, assetData in pairs(gameData) do if not resName or resName == index then if assetData.resList then for _,data in ipairs(assetData.resList) do if assetData.useInstantiate then GameObject.DestroyImmediate(data) end end end if assetData.game then for i = 1, assetData.refCount do resMgr:UnLoadAsset(assetData.game, index) end end assetData.refCount = 0 assetData.resList = {} -- deleteTable[#deleteTable + 1] = tempIndex end tempIndex = tempIndex + 1 end end end --endregion