local Base = require("Battle/Logic/Level/LevelItemFactory/LevelItem") local LevelItem_Trigger = class("LevelItem_Trigger", Base) local EventSystem = require('Event/EventSystem') local ColliderManager = require("Battle/Logic/Level/ColliderManager") local BattleEffect = require("Battle/Logic/BattleEffect/BattleEffect") local ipairs = ipairs local table_insert = table.insert local table_remove = table.remove local table_clearArray = table.clearArray local LogicUpdateManager = LogicUpdateManager local string_isNilOrEmpty = string.isNilOrEmpty local LuaConst = LuaConst local ExpEntity = require "Battle/Expression/ExpEntity/ExpEntity" local TempTable = LuaExt.CreateTable(1) local TriggerCharacterType = { AllPlayer = 1, -- 所有玩家 AnyCharacter = 3, -- 任意角色 GivenMonster = 4, -- 指定怪物 PlayerByBorn = 5, -- 指定出生点玩家 PlayerByCamp = 6, -- 指定阵营玩家 } --region --***************生命周期***************-- function LevelItem_Trigger:initialize(data) Base.initialize(self,data) self._triggerCount = data.CharacterNumber or 1 self._battleEffectID = data.BattleEffectID self._beCD = data.BattlEffectCDFrame --发动BattleEffect的CD(帧数) self._beCDOverFrame = 0 if data.ColliderType == LuaConst.LevelShapeType.Circle then self._colliderID = ColliderManager.CreateCircleCollider(data.ItemPos,data.Radius * data.Radius) elseif data.ColliderType == LuaConst.LevelShapeType.Square then self._colliderID = ColliderManager.CreateRectCollider(data.ItemPos,data.ItemDir,data.Length,data.Width) end ColliderManager.AddEnterEvent(self._colliderID,self.OnEnterEvent,self) ColliderManager.AddExitEvent(self._colliderID,self.OnExitEvent,self) self._enterEntityIDs = nil if self._battleEffectID and self._battleEffectID > 0 then self._enterEntityIDs = {} end self._exitEntityIDs = nil self._stayParam = nil self._stayUpdateAgent = nil self._triggerEntityIDs = nil self._context = { HasExecutors = function() return self._triggerEntityIDs ~= nil end, IterExecutors = function() return ipairs(self._triggerEntityIDs) end, } self.isAllHeroJoinBattle = LevelManager.CurLevelFunc:IsAllHeroJoinBattle() if data.ModelID and data.ModelID > 0 then local layer = LuaConst.Layer.NPC_Function local camp = LuaConst.ECampID.NEUTRAL_PEACE local modelData = DataSheetManager.MonsterModelData:GetDataByID(data.ModelID) local px, pz = FP.tonumberV2(self.ItemData.ItemPos) local dx, dz = FP.tonumberV2(self.ItemData.ItemDir) local renderEntity = ExpEntity.LoadRenderEntity(modelData, false, px, pz, dx, dz, not LevelManager.IsNoBattleLevel(), layer, camp, -1) self.renderEntity = renderEntity if renderEntity then self._triggerAnim = data.TriggerAnim self._exitTriggerAnim = data.ExitTriggerAnim end end end function LevelItem_Trigger:OnActive() if Base.OnActive(self) then self:ClearTriggerInfos() local characterType = self.ItemData.CharacterType if characterType ==TriggerCharacterType.AllPlayer then ColliderManager.ActiveCollider(self._colliderID, LogicUpdateManager.ValidSyncEntityIter) self._isPlayerTrigger = true elseif characterType == TriggerCharacterType.AnyCharacter then ColliderManager.ActiveCollider(self._colliderID, LogicUpdateManager.ValidAllEntityIter) elseif characterType == TriggerCharacterType.GivenMonster then self._monsterDic = self:TryFindMonster(self.ItemData.MonsterID) EventSystem.Regist(EventID.Level_MonsterBorn, self.AddMonsterList, self) EventSystem.Regist(EventID.Level_MonsterDead, self.RemoveMonsterList, self) ColliderManager.ActiveCollider(self._colliderID,self.MonsterIter,self) elseif characterType == TriggerCharacterType.PlayerByBorn then ColliderManager.ActiveCollider(self._colliderID,self.PlayerByBornIter,self) self._isPlayerTrigger = true elseif characterType == TriggerCharacterType.PlayerByCamp then ColliderManager.ActiveCollider(self._colliderID,self.PlayerByCampIter,self) self._isPlayerTrigger = true end EventSystem.Dispatch(EventID.BI_LevelMiddle,BIManager.BIType.LevelLayout,self.LevelItemID,1,"Trigger Active") return true end end function LevelItem_Trigger:OnDeactive() if Base.OnDeactive(self) then ColliderManager.DeActiveCollider(self._colliderID) local characterType = self.ItemData.CharacterType if characterType == TriggerCharacterType.GivenMonster then EventSystem.UnRegist(EventID.Level_MonsterBorn, self.AddMonsterList, self) EventSystem.UnRegist(EventID.Level_MonsterDead, self.RemoveMonsterList, self) self._monsterDic = nil end self:ClearTriggerInfos() EventSystem.Dispatch(EventID.BI_LevelMiddle,BIManager.BIType.LevelLayout,self.LevelItemID,1,"Trigger Deactive") return true end end function LevelItem_Trigger:OnDestroy() Base.OnDestroy(self) ColliderManager.DestroyCollider(self._colliderID) if self.renderEntity then self.renderEntity:Dispose(false) end self._colliderID = nil self._isPlayerTrigger = nil self._enterEntityIDs = nil self._exitEntityIDs = nil self._stayParam = nil self._stayUpdateAgent = nil end function LevelItem_Trigger:OnUpdate() if self._battleEffectID then if self._enterEntityIDs and #self._enterEntityIDs > 0 then local entity = LogicUpdateManager._entityDic[self._enterEntityIDs[1]] if entity and entity:IsActive() and entity:IsAlive() then if not self:IsBattleEffectInCD() then self:ExecuteBattleEffect(entity) end end end end if self._stayUpdateAgent then self:_stayUpdateAgent() end end --endregion 生命周期 --这个Trigger是否处于CD中(不可触发状态) function LevelItem_Trigger:IsBattleEffectInCD() local result = false if self._beCDOverFrame and self._beCDOverFrame > LogicUpdateManager._clientHandleFrame then result = true end return result end --region --***************事件相关***************-- function LevelItem_Trigger:DoAction(actionType, match) Base.DoAction(self,actionType) if actionType == LuaConst.LevelActionType.Trigger_Active then self:OnActive() elseif actionType == LuaConst.LevelActionType.Trigger_Deactive then self:OnDeactive() end end function LevelItem_Trigger:HandleCondition(conditionType,paramId,param1) Base.HandleCondition(conditionType,paramId,param1) if not self._colliderID then logging.error(LTAG.ERROR, "Can't Find Collider In Trigger Item--ItemID:", self.LevelItemID) return end if conditionType == LuaConst.LevelConditionType.Trigger_Enter then self._enterEntityIDs = self._enterEntityIDs or {} elseif conditionType == LuaConst.LevelConditionType.Trigger_Exit then self._exitEntityIDs = self._exitEntityIDs or {} elseif conditionType == LuaConst.LevelConditionType.Trigger_Stay then if not self._stayParam then if self.ItemData.CharacterNumber then self._stayParam = { number = 0, entityIDs= {}, stayTime = FP.newV1(0) } else self._stayParam = { entityIDs= {}, stayTimes = {} } end end elseif conditionType == LuaConst.LevelConditionType.Trigger_PlayerStayNumber then self._enterEntityIDs = self._enterEntityIDs or {} self._exitEntityIDs = self._exitEntityIDs or {} end end --endregion 事件相关 --region --***************内部方法***************-- function LevelItem_Trigger:OnEnterEvent(entity) local entityID = entity.EntityID if self._enterEntityIDs then self:HandleEnter(true, entityID) end if self._exitEntityIDs then self:HandleExit(true, entityID) end if self._stayParam then self:HandleStay(true, entityID) end if not self:IsBattleEffectInCD() then if self._battleEffectID then self:ExecuteBattleEffect(entity) end end EventSystem.Dispatch(EventID.Level_EnterTriggerItem, self.LevelItemID, entity) end function LevelItem_Trigger:ExecuteBattleEffect(target) local outParams = {levelItem = self} BattleEffect.ExecuteByEffectId(self._battleEffectID, outParams, target, target) if self._beCD then self._beCDOverFrame = LogicUpdateManager._clientHandleFrame + self._beCD end end function LevelItem_Trigger:OnExitEvent(entity) local entityID = entity.EntityID if self._enterEntityIDs then self:HandleEnter(false, entityID) end if self._exitEntityIDs then self:HandleExit(false, entityID) end if self._stayParam then self:HandleStay(false, entityID) end end function LevelItem_Trigger:TryPlayEnterAnim(entity, entityID) if self.renderEntity then if #self._enterEntityIDs == 1 then if not string_isNilOrEmpty(self._triggerAnim) then local animIntKey= UTL.String.GetIdByString(self._triggerAnim) if animIntKey then self.renderEntity:PlayAnimation(animIntKey, false, false, 0) end end end end end function LevelItem_Trigger:HandleEnter(enter, entityID) if enter then table_insert(self._enterEntityIDs, entityID) self:TryPlayEnterAnim(entity, entityID) local count = self.ItemData.CharacterNumber local entityNum = #self._enterEntityIDs if not count or entityNum == count then self._triggerEntityIDs = self._enterEntityIDs self:Dispatch(LuaConst.LevelConditionType.Trigger_Enter, self._context) if self._isPlayerTrigger then self:Dispatch(LuaConst.LevelConditionType.Trigger_PlayerStayNumber,nil, entityNum) end self._triggerEntityIDs = nil if not self._battleEffectID or self._battleEffectID <= 0 then table_clearArray(self._enterEntityIDs) end EventSystem.Dispatch(EventID.BI_LevelMiddle,BIManager.BIType.LevelLayout,self.LevelItemID,1,"Trigger Enter") end else for i = 1, #self._enterEntityIDs do local id = self._enterEntityIDs[i] if id == entityID then table_remove(self._enterEntityIDs,i) break end end self:TryPlayExitAnim(entity, entityID) end end function LevelItem_Trigger:TryPlayExitAnim(entity, entityID) if self.renderEntity then if #self._enterEntityIDs == 0 then if not string_isNilOrEmpty(self._exitTriggerAnim) then local animIntKey= UTL.String.GetIdByString(self._exitTriggerAnim) if animIntKey then self.renderEntity:PlayAnimation(animIntKey, false, false, 0) end end end end end function LevelItem_Trigger:HandleExit(enter, entityID) if enter then for i = 1, #self._exitEntityIDs do local id = self._exitEntityIDs[i] if id == entityID then table_remove(self._exitEntityIDs,i) break end end else table_insert(self._exitEntityIDs, entityID) local count = self.ItemData.CharacterNumber local entityNum = #self._exitEntityIDs if not count or entityNum == count then self._triggerEntityIDs = self._exitEntityIDs self:Dispatch(LuaConst.LevelConditionType.Trigger_Exit, self._context) if self._isPlayerTrigger then self:Dispatch(LuaConst.LevelConditionType.Trigger_PlayerStayNumber,self._context, -entityNum) end self._triggerEntityIDs = nil table_clearArray(self._exitEntityIDs) EventSystem.Dispatch(EventID.BI_LevelMiddle,BIManager.BIType.LevelLayout,self.LevelItemID,1,"Trigger Exit") end end end function LevelItem_Trigger:HandleStay(enter, entityID) local param = self._stayParam local count = self.ItemData.CharacterNumber if enter then if count then param.number = param.number + 1 table_insert(param.entityIDs, entityID) if param.number == self._triggerCount then param.stayTime:Reset() self._stayUpdateAgent = self.StayUpdateWithCount end else table_insert(param.entityIDs, entityID) table_insert(param.stayTimes, FP.newV1(0)) if not self._stayUpdateAgent then self._stayUpdateAgent = self.StayUpdateNoCount end end else if count then if param.number == self._triggerCount then param.stayTime:Reset() self._stayUpdateAgent = nil end for i = 1, #param.entityIDs do local id = param.entityIDs[i] if id == entityID then table_remove(param.entityIDs,i) param.number = param.number - 1 break end end else for i = 1, #param.entityIDs do local id = param.entityIDs[i] if id == entityID then table_remove(param.entityIDs,i) table_remove(param.stayTimes,i) break end end if #param.entityIDs == 0 then self._stayUpdateAgent = nil end end end end function LevelItem_Trigger:StayUpdateWithCount() local param = self._stayParam param.stayTime:Add(LuaConst.TimeSpan) self._triggerEntityIDs = param.entityIDs self:Dispatch(LuaConst.LevelConditionType.Trigger_Stay,self._context, param.stayTime) self._triggerEntityIDs = nil end function LevelItem_Trigger:StayUpdateNoCount() local param = self._stayParam for i, id in ipairs(param.entityIDs) do local stayTime = param.stayTimes[i] stayTime:Add(LuaConst.TimeSpan) TempTable[1] = id self._triggerEntityIDs = TempTable self:Dispatch(LuaConst.LevelConditionType.Trigger_Stay,self._context, stayTime) self._triggerEntityIDs = nil end end function LevelItem_Trigger:ClearTriggerInfos() if self._enterEntityIDs then table_clearArray(self._enterEntityIDs) end if self._exitEntityIDs then table_clearArray(self._exitEntityIDs) end if self._stayParam then table_clearArray(self._stayParam.entityIDs) self._stayParam.stayTime:Reset() self._stayUpdateAgent = nil end end function LevelItem_Trigger:TryFindMonster(monsterID) local entityDic = {} for _, entity in pairs(LogicUpdateManager._entityDic) do if entity._logicInitData.CharacterID == monsterID then entityDic[entity.EntityID] = entity end end return entityDic end function LevelItem_Trigger:AddMonsterList(monsterID, entityID) if monsterID == self.ItemData.MonsterID then self._monsterDic[entityID] = LogicUpdateManager._entityDic[entityID] end end function LevelItem_Trigger:RemoveMonsterList(monsterID, entityID) if monsterID == self.ItemData.MonsterID then self._monsterDic[entityID] = nil end end function LevelItem_Trigger:MonsterIter() return pairs(self._monsterDic) end function LevelItem_Trigger:PlayerByBornIter() return LevelItem_Trigger.BornItemIPair, self, 0 end function LevelItem_Trigger:PlayerByCampIter() return LevelItem_Trigger.CampIPair, self, 0 end function LevelItem_Trigger:BornItemIPair(i) while true do i = i + 1 local entity = LogicUpdateManager.EntityList_Sync[i] if entity then if self.ItemData.MatchDic[entity._logicInitData.BornItemID] then return i, entity end else break end end end function LevelItem_Trigger:CampIPair(i) while true do i = i + 1 local entity = LogicUpdateManager.EntityList_Sync[i] if entity then if self.isAllHeroJoinBattle or entity:IsMainEntityOfPlayer() then if self.ItemData.MatchDic[entity:GetCampID()] then return i, entity end end else break end end end --endregion 内部方法 return LevelItem_Trigger