local Base = require("Battle/Logic/Level/LevelItemFactory/LevelItem") local LevelItem_StrongHold = class("LevelItem_StrongHold", Base) local EventSystem = require('Event/EventSystem') local VisualObject = require("Battle/Expression/VisualObject") local ColliderManager = require("Battle/Logic/Level/ColliderManager") local LuaConst = LuaConst local FP_Const_Zero = FP.Const.Zero local LogicUpdateManager = LogicUpdateManager local OccupyStage = { Staying = 0, -- 僵持中阶段(或无人占领阶段) Snatching = 1, -- 抢夺中阶段 Occupying = 2, -- 占领中阶段 Occupied = 3, -- 已占领阶段 } function LevelItem_StrongHold:initialize(data) Base.initialize(self,data) 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.OnTriggerEnter,self) ColliderManager.AddExitEvent(self._colliderID,self.OnTriggerExit,self) if data.UIShowRadius and data.UIShowRadius > FP.Const.Zero then self._uiShowColliderID = ColliderManager.CreateCircleCollider(data.ItemPos, data.UIShowRadius * data.UIShowRadius) ColliderManager.AddEnterEvent(self._uiShowColliderID, self.OnUIShowTriggerEnter, self) ColliderManager.AddExitEvent(self._uiShowColliderID, self.OnUIShowTriggerExit, self) end self._curOccupierID = nil --this field is allowed to be nil -- 改值为nil时 <=> 不改变进度(进度不涨也不降) self._curStage = nil self._timer = FP.newV1(0) self._inSuspend = false -- 下面为主视角字段,注意使用 self._mainSelf = nil self.leadingOccupierID = nil --占领领先一方的ID self._entityIDList = {} end function LevelItem_StrongHold:GetCurOccupierID() return self.leadingOccupierID end function LevelItem_StrongHold:GetStrongHoldInfo() return self._curStage ,self.leadingOccupierID ,FP.tonumberV1(self._timer / self.ItemData.OccupyDuration) end --region --***************生命周期***************-- function LevelItem_StrongHold:OnActive() if not self.IsActive then self.IsActive = true EventSystem.Regist(self.LevelItemID..EventID._OccupierChanged, self.OnOccupierChanged, self) local itemData = self.ItemData local px, pz = FP.tonumberV2(itemData.ItemPos) local dx, dz = FP.tonumberV2(itemData.ItemDir) if itemData.Effect then self._effect = VisualObject.CreateEffectObject(itemData.Effect,ExpLevelManager.SceneObjParent) self._effect:SetPositionAndDirection(dx, dz,px, 0, pz) end if itemData.Object then self._object = VisualObject.CreateOccupyObject(itemData.Object, ExpLevelManager.SceneObjParent, FP.tonumberV1(itemData.OccupyDuration)) self._object:SetPositionAndDirection(dx, dz,px, 0, pz) end end self:ActiveOccupy() self._curStage = OccupyStage.Staying self._curOccupierID = nil self._mainSelf = nil self._inSuspend = false self:ShowNeutralExpression() return true end function LevelItem_StrongHold:OnDeactive() if self.IsActive then self.IsActive = false EventSystem.UnRegist(self.LevelItemID..EventID._OccupierChanged, self.OnOccupierChanged, self) if self._effect then self._effect:Dispose() self._effect = nil end if self._object then self._object:Dispose() self._object = nil end end if self._colliderID then ColliderManager.DeActiveCollider(self._colliderID) end if self._uiShowColliderID then ColliderManager.DeActiveCollider(self._uiShowColliderID) end self._inSuspend = false return true end function LevelItem_StrongHold:OnDestroy() Base.OnDestroy(self) self._curOccupierID = nil self._curStage = nil self._timer = nil self._entityIDList = nil if self._colliderID then ColliderManager.DestroyCollider(self._colliderID) end if self._uiShowColliderID then ColliderManager.DestroyCollider(self._uiShowColliderID) end end function LevelItem_StrongHold:OnUpdate() if self._curStage == OccupyStage.Snatching then self._timer:Sub(LuaConst.TimeSpan) if self._timer <= FP_Const_Zero then self:StartOccupy() end EventSystem.Dispatch(EventID.UI_MiniMapMain_StrongHold_Occupation, self.LevelItemID) elseif self._curStage == OccupyStage.Occupying then self._timer:Add(LuaConst.TimeSpan) if self._timer >= self.ItemData.OccupyDuration then self:CompleteOccupy() end EventSystem.Dispatch(EventID.UI_MiniMapMain_StrongHold_Occupation, self.LevelItemID) end end --endregion 生命周期 --region --***************事件相关***************-- function LevelItem_StrongHold:DoAction(actionType, match, param1, param2) if actionType == LuaConst.LevelActionType.StrongHold_Active then if self._colliderID then ColliderManager.DeActiveCollider(self._colliderID) end if self._uiShowColliderID then ColliderManager.DeActiveCollider(self._uiShowColliderID) end self:OnActive() elseif actionType == LuaConst.LevelActionType.StrongHold_Deactive then self:OnDeactive() elseif actionType == LuaConst.LevelActionType.StrongHold_ChangeToNeutral then self:ChangeToNeutral() EventSystem.Dispatch(EventID.Level_StrongHoldChangeStageAction, self.LevelItemID) elseif actionType == LuaConst.LevelActionType.HandleBuff then local checkFunc = LevelItemManager.MatchCheckFunc if param1 then for i, entityID in ipairs(self._entityIDList) do local entity = LogicUpdateManager._entityDic[entityID] if entity and checkFunc[match.Check](entity, match.Param) then SystemManager.AddBuff(entity, param2, nil, nil, nil) end end else for i, entityID in ipairs(self._entityIDList) do local entity = LogicUpdateManager._entityDic[entityID] if entity and checkFunc[match.Check](entity, match.Param) then SystemManager.DeleteBuff(entity, param2, nil) end end end end end function LevelItem_StrongHold:OnTriggerEnter(entity) table.insert(self._entityIDList, entity.EntityID) EventSystem.Dispatch(EventID.Level_ItemTriggerOccupy, self.LevelItemID, entity, true, self._inSuspend) end function LevelItem_StrongHold:OnTriggerExit(entity) table.removebyvalue(self._entityIDList, entity.EntityID) EventSystem.Dispatch(EventID.Level_ItemTriggerOccupy, self.LevelItemID, entity, false, self._inSuspend) end function LevelItem_StrongHold:OnUIShowTriggerEnter(entity) EventSystem.Dispatch(EventID.Level_StrongHoldShowUIAreaEnter, self.LevelItemID, entity, true, self._inSuspend) end function LevelItem_StrongHold:OnUIShowTriggerExit(entity) EventSystem.Dispatch(EventID.Level_StrongHoldShowUIAreaExit, self.LevelItemID, entity, false, self._inSuspend) end function LevelItem_StrongHold:OnOccupierChanged(occupierID, mainSelf) if occupierID == -1 then self:FallStay(self._curOccupierID) self._curOccupierID = nil self._mainSelf = nil else self._curOccupierID = occupierID self._mainSelf = mainSelf if self.ItemData.OccupyDuration <= FP_Const_Zero then self:CompleteOccupy() else if self._timer > FP_Const_Zero and occupierID ~= self.leadingOccupierID then self:StartSnatch() elseif self._timer < self.ItemData.OccupyDuration then self:StartOccupy() end end end end --endregion 事件相关 --region --***************内部方法***************-- function LevelItem_StrongHold:_SetCurStage(newStage) self._curStage = newStage end --陷入僵持,包括两种情况 1、从 「有人在据点内」 转变为 「无人在据点内」 时 2、从 「人数不相等」 转变为 「人数相等」 时 function LevelItem_StrongHold:FallStay(oldOccupierID) self:_SetCurStage(OccupyStage.Staying) --停止升降旗表现 self:ShowProgressExpression(0) end --开始夺取,指的是进度开始下降 function LevelItem_StrongHold:StartSnatch() self:_SetCurStage(OccupyStage.Snatching) --播放降旗表现 self:ShowProgressExpression(-1) end --开始占领, 指的是进度开始涨 function LevelItem_StrongHold:StartOccupy() if self.ItemData.NeedChangeToNeutral then if self._curOccupierID ~= self.leadingOccupierID then self:ChangeToNeutral() end end self.leadingOccupierID = self._curOccupierID self:_SetCurStage(OccupyStage.Occupying) --播放升旗表现 self:ShowProgressExpression(1) end function LevelItem_StrongHold:ChangeToNeutral() self.leadingOccupierID = nil self._timer:Reset() self:_SetCurStage(OccupyStage.Staying) self:ShowNeutralExpression() self:Dispatch(LuaConst.LevelConditionType.StrongHold_ChangeToNeutral) end --完成占领 function LevelItem_StrongHold:CompleteOccupy() --根据LevelItem_StrongHold的类型,self._curOccupierID有不同的含义,比如campID、playerID self:Dispatch(LuaConst.LevelConditionType.StrongHold_UpdateOccupy,nil, self._curOccupierID) BattleEventSystem.OnStrongholdCompleteOccupy(self.ItemData.ItemPos:cloneV2(), self._curOccupierID, self.ItemData.OccupyRule) self._timer:Reset(self.ItemData.OccupyDuration) self:_SetCurStage(OccupyStage.Occupied) if self.ItemData.IsSuspend then --根据配置决定占领成功后是否需要挂起 self:SuspendOccupy() end --播放占领后的表现 self:ShowCompleteExpression() end --激活占领 function LevelItem_StrongHold:ActiveOccupy() if self._colliderID then --当前只需要用同步玩家触发collider,后面有需求可以扩展 ColliderManager.ActiveCollider(self._colliderID, LogicUpdateManager.ValidSyncEntityIter) end if self._uiShowColliderID then ColliderManager.ActiveCollider(self._uiShowColliderID, LogicUpdateManager.ValidSyncEntityIter) end end --挂起占领:仅表示进度不再变化。一些基础功能依然要运行,比如统计据点内人数(由LevelTerritoryModule统计)。所以collider在suspend时不能禁用,事件也得抛出,并且LevelTerritoryModule需要处理 function LevelItem_StrongHold:SuspendOccupy() self._inSuspend = true EventSystem.Dispatch(EventID.Level_ItemSuspendOccupy, self.LevelItemID) end function LevelItem_StrongHold:ShowProgressExpression(state) if not self._object then return end if state > 0 then local shows = self.ItemData.OccupyShows local appendObject = shows and shows[self._curOccupierID].AppendObject or nil self._object:Invoke("PlayForward", appendObject) elseif state == 0 then self._object:Invoke("Pause") elseif state < 0 then self._object:Invoke("PlayBackward") end end function LevelItem_StrongHold:ShowNeutralExpression() if self._effect then self._effect:SetColor(0.6741,0.7162,0.75) end end function LevelItem_StrongHold:ShowCompleteExpression() if not self._effect then return end -- OccupyShows 为空时使用主视角的显隐判断 if self.ItemData.OccupyShows then local show = self.ItemData.OccupyShows[self._curOccupierID] if not show then if self._mainSelf then show = self.ItemData.OccupyShows[-1] else show = self.ItemData.OccupyShows[-2] end end if show then local color = show.EffectColor self._effect:SetColor(color.r,color.g,color.b) else logging.error(LTAG.ERROR, "HYW : 获取据点占领颜色失败!!! LevelItemID : ", LevelItemID, " self._curOccupierID : ", self._curOccupierID) end else if self._mainSelf then self._effect:SetColor(0.0156,0.5619,0.9921) else self._effect:SetColor(1,0,0) end end end --endregion 内部方法 return LevelItem_StrongHold