local ColliderManager = {} local private = { _activeDic = {}, _prepareDic = {}, _activeList = {}, --用来遍历的List,之前遍历的_activeDic会导致不一致,改为遍历List 2022年6月7日 HYW } local totalID = 0 local ConstZero = FP.Const.Zero local ConstNegOne = FP.Const.NegOne local FP_IsDistanceSqrGreater = FP.V2.IsDistanceSqrGreater local FP_IsInRectRange = FP.V2.IsInRectRange local function CheckAllCover() return true end local function CheckCircle(collider, entity) local pos = entity.components.move.LogicPos return not FP_IsDistanceSqrGreater(pos, collider.pos, collider.radiusSqr) end local function CheckRect(collider, entity) local pos = entity.components.move.LogicPos return FP_IsInRectRange(pos,collider.pos,collider.dir,collider.length,collider.width) end function ColliderManager.CreateRectCollider(pos,dir,length,width) if length <= ConstZero or width <= ConstZero then return end totalID = totalID + 1 private._prepareDic[totalID] = { pos = pos, dir = dir, length = length, width = width, inColliderList = {}, checkFunc = CheckRect, ID = totalID } return totalID end function ColliderManager.CreateCircleCollider(pos,radiusSqr) if radiusSqr == ConstNegOne then totalID = totalID + 1 private._prepareDic[totalID] = { inColliderList = {}, checkFunc = CheckAllCover, ID = totalID} return totalID elseif radiusSqr > ConstZero then totalID = totalID + 1 private._prepareDic[totalID] = {pos = pos, radiusSqr = radiusSqr, inColliderList = {}, checkFunc = CheckCircle, ID = totalID} return totalID end end function ColliderManager.ActiveCollider(id,iter,iterOwner) local collider = private._prepareDic[id] if collider then private._prepareDic[id] = nil if private._activeDic[id] == nil then table.insert(private._activeList, collider) end private._activeDic[id] = collider collider.iter = iter collider.iterOwner = iterOwner end end function ColliderManager.DeActiveCollider(id) local collider = private._activeDic[id] if collider then private._activeDic[id] = nil for i,v in ipairs(private._activeList) do if v.ID == id then table.remove(private._activeList, i) break end end private._prepareDic[id] = collider private.OnDisableCollider(collider, LuaConst.EColliderExitReason.DEACTIVE) end end function ColliderManager.DestroyCollider(id) local collider = private._activeDic[id] private._activeDic[id] = nil for i,v in ipairs(private._activeList) do if v.ID == id then table.remove(private._activeList, i) break end end private._prepareDic[id] = nil if collider then private.OnDisableCollider(collider, LuaConst.EColliderExitReason.DESTROY) collider.isDestroyed = true end end function ColliderManager.UpdatePos(id , pos) local collider = private._activeDic[id] if collider then collider.pos:Reset(pos) end end function ColliderManager.AddEnterEvent(id,func,self) local collider = private._prepareDic[id] or private._activeDic[id] if collider then collider.enterFunc = func collider.enterOwner = self end end function ColliderManager.AddStayEvent(id,func,self) local collider = private._prepareDic[id] or private._activeDic[id] if collider then collider.stayFunc = func collider.stayOwner = self end end function ColliderManager.AddExitEvent(id,func,self) local collider = private._prepareDic[id] or private._activeDic[id] if collider then collider.exitFunc = func collider.exitOwner = self end end function ColliderManager.OnUpdate() --for k, collider in pairs(private._activeDic) do --old 遍历字典,会导致不一致 for i,collider in ipairs(private._activeList) do --new 遍历List private.HandleCollider(collider) end end function ColliderManager.Clear() totalID = 0 table.clear(private._activeDic) table.clear(private._activeList) table.clear(private._prepareDic) end function ColliderManager.CheckInCollider(id, entity) local collider = private._activeDic[id] if collider then for _, v in ipairs(collider.inColliderList) do if v.entity == entity then return true end end end return false end function ColliderManager.GetInColliderCount(id) local collider = private._activeDic[id] if collider then return #collider.inColliderList end return 0 end function private.HandleCollider(collider) local list = collider.inColliderList for _, entity in collider.iter(collider.iterOwner) do local info for i,v in ipairs(list) do if v.entity == entity then info = v break end end if collider.checkFunc(collider,entity) then if info then info.invoke = private.StayInvoke else info = { entity = entity, invoke = private.EnterInvoke} table.insert(list , info) end end end for i = #list, 1, -1 do if not collider.isDestroyed then local info = list[i] if info then local entity = info.entity if info.invoke then info.invoke(collider,entity) info.invoke = nil else table.remove(list, i) private.ExitInvoke(collider, entity) end --else --do nothing info.invoke 可能改变 list ,所以有可能包含空(最常见的情况是 private.OnDisableCollider 导致 list 被清空) end end end end function private.OnDisableCollider(collider, disableReason) for i,info in ipairs(collider.inColliderList) do if collider.exitFunc then if collider.exitOwner then collider.exitFunc(collider.exitOwner ,info.entity, disableReason) else collider.exitFunc(info.entity, disableReason) end end end table.clearArray(collider.inColliderList) end function private.EnterInvoke(collider, entity) if collider.enterFunc then if collider.enterOwner then collider.enterFunc(collider.enterOwner ,entity) else collider.enterFunc(entity) end end end function private.StayInvoke(collider, entity) if collider.stayFunc then if collider.stayOwner then collider.stayFunc(collider.stayOwner, entity) else collider.stayFunc(entity) end end end function private.ExitInvoke(collider, entity) if collider.exitFunc then if collider.exitOwner then collider.exitFunc(collider.exitOwner, entity) else collider.exitFunc(entity) end end end return ColliderManager