-- 多交互按钮排布先按照配置顺序来,如果以后策划有需求要跳着放置按钮,需要策划加个坑位的字段。 -- 按钮位置,不要让策划填写UI偏移量 ,以为一些界面调整或者动态变化的话,排布有问题 ,所以需要UE提前摆好位置。 -- 定义术语 :A 操作 B ;A - 交互者 ,B - 交互物 local EventSystem = require('Event/EventSystem') local InteractComponent = class("InteractComponent") local ColliderManager = require("Battle/Logic/Level/ColliderManager") local BattleEffect = require"Battle/Logic/BattleEffect/BattleEffect" local EInteractState = LuaConst.EInteractState function InteractComponent:initialize(entity) self.Entity = entity --- 我是碰撞人(交互者)代码 ↓ --我撞到的交互物(这个是 交互物和我发生碰撞后 ,我保存的交互物的entity ) ,如果一个交互物有两种交互且范围不同 ,则这个数据中只塞入一次交互物entity ,再次进入同交互物的不同范围时不放入 。操作时有其操作index查交互信息。 self.InteractEntityList = {} self.InteractingData = nil -- 我正在与我的交互物发生交互行为的数据(如:交互物有3中交互,正与其做第二个交互行为 ,则这个值是第二个交互数据) self.InteractingIndex = nil --我正在交互的按钮的index (index指的是当前self.InteractingData.ID在MonsterFeature表的InteractIDs里的index) self.InteractColliderEnterDic = {} -- 我触发了交互物的功能个数 self.CurCmdOpInteractEntity = nil -- 当前cmd指令要操作的交互物 (UI按钮点击后与玩家与哪个东西交互) self.lastTriggerInteractEntity = nil -- 获取最新被我进入的交互物 (目的:为了给condition判断使用,仅此而已) --- 我是碰撞人(交互者)代码 ↑ --- 我是交互物(一个物体多个交互功能) 代码↓ self.InteractDatas = nil -- 所有的交互功能 self.colliderIDs = nil -- 所有的交互功能对应的碰撞盒 self.colliderID2InteractDataDic = nil --所有的碰撞盒对应的交互数据 self.interactState = EInteractState.NO_INTERACT local featureData = entity.components.base.CurMonsterFeature local interactCount = #featureData.InteractIDs if interactCount > 0 then self.InteractDatas = {} self.colliderIDs = {} self.colliderID2InteractDataDic = {} for i = 1, interactCount do local interactID = featureData.InteractIDs[i] local interactData = DataSheetManager.InteractData:GetDataByID(interactID) local colliderID = ColliderManager.CreateCircleCollider(entity.components.move.LogicPos:cloneV2(),interactData.InteractRange) local enterCallBack = function(triggerEntity) self:OnInteractColliderEnter(triggerEntity, interactData, self.Entity) end local exitCallBack = function(triggerEntity, exitReason) self:OnInteractColliderExit(triggerEntity, exitReason, interactData, self.Entity) end ColliderManager.AddEnterEvent(colliderID, enterCallBack ) ColliderManager.AddExitEvent(colliderID, exitCallBack) table.insert(self.InteractDatas, interactData) table.insert(self.colliderIDs, colliderID) self.colliderID2InteractDataDic[colliderID] = interactData end end --- 我是交互物 代码↑ end function InteractComponent:GetCmdOpInteractEntity() return self.CurCmdOpInteractEntity end function InteractComponent:SetCmdOpInteractEntity(interactEntity) self.CurCmdOpInteractEntity = interactEntity end --获取最新被我撞到的人 function InteractComponent:GetLastInteractEntity() return self.lastTriggerInteractEntity end -- 获取最早被我撞到的人 function InteractComponent:GetFirstInteractEntity() return self.InteractEntityList[1] end --set被我撞到的人-enter function InteractComponent:AddInteractEntity(entity) self.lastTriggerInteractEntity = entity if not table.containValue(self.InteractEntityList, entity) then table.insert(self.InteractEntityList ,entity) end self.InteractColliderEnterDic[entity] = self.InteractColliderEnterDic[entity] and (self.InteractColliderEnterDic[entity] + 1) or 1 end --set被我撞到的人 - exit ;返回是否全部清空 function InteractComponent:RemoveInteractEntity(entity) if self.InteractColliderEnterDic[entity] then self.InteractColliderEnterDic[entity] = self.InteractColliderEnterDic[entity] - 1 if self.InteractColliderEnterDic[entity] == 0 then table.removebyvalue(self.InteractEntityList ,entity, true) self.InteractColliderEnterDic[entity] = nil return true end end return false end --set 我正在发生的交互行为 function InteractComponent:SetInteractingData(interactData, interactIndex) self.InteractingData = interactData self.InteractingIndex = interactIndex end --get 我正在发生的交互行为 function InteractComponent:GetInteractingData() return self.InteractingData, self.InteractingIndex end --- 交互物代码 ↓ function InteractComponent:GetColliderIDs() return self.colliderIDs end function InteractComponent:GetAllInteractData() return self.InteractDatas end function InteractComponent:HasInteractData() return self.InteractDatas and #self.InteractDatas > 0 end function InteractComponent:GetInteractDataByColliderID(colliderID) return self.colliderID2InteractDataDic[colliderID] end -- interactIndex 就是monsterFeature表中填写的 interactIDs{ }的顺序 function InteractComponent:GetInteractData(interactIndex) return self.InteractDatas[interactIndex] end function InteractComponent:SetInteractState(newState) if self.interactState ~= newState then self.interactState = newState end end function InteractComponent:GetInteractIndexByData(interactData) local index = -1 for i,info in ipairs(self.InteractDatas) do if info == interactData then index = i break end end return index end --- 交互物代码 ↑ function InteractComponent:GetInteractState() return self.interactState end function InteractComponent:OnInteractColliderEnter(triggerEntity, interactData, entity) triggerEntity:AddInteractEntity(entity) if entity.isPickupItem then if triggerEntity.isHero then if interactData.InteractEffect > 0 then BattleEffect.ExecuteByEffectId(interactData.InteractEffect, nil, entity, triggerEntity) end SystemManager.DeadQuit(entity) end else local triggerInteractComp = triggerEntity.components.interact local curCmdOpInteractEntity = triggerInteractComp:GetCmdOpInteractEntity() local conditionTree = ConditionManager.GetConditionDataTree(interactData.UIConditionStr) if ConditionManager.MeetCondition(triggerEntity, conditionTree) then if curCmdOpInteractEntity == nil then triggerInteractComp:SetCmdOpInteractEntity(entity) curCmdOpInteractEntity = entity end if curCmdOpInteractEntity == entity then local interactIndex = 0 for i,data in ipairs(self.InteractDatas) do if data.ID == interactData.ID then interactIndex = i break end end EventSystem.Dispatch(EventID.UI_Interact_Show, true ,interactData ,triggerEntity , entity, interactIndex) end end end end function InteractComponent:OnInteractColliderExit(triggerEntity, exitReason, interactData ,entity) local interactEntity = entity local triggerInteractComp = triggerEntity.components.interact local curCmdOpInteractEntity = triggerInteractComp:GetCmdOpInteractEntity() if curCmdOpInteractEntity == interactEntity then -- 如果当前正在交互中 ,距离远了,则中断交互 if triggerInteractComp:IsInteracting() then local abortReason = nil if exitReason == LuaConst.EColliderExitReason.DESTROY then abortReason = LuaConst.EInteractAbortReason.DESTROYED end SystemManager.InteractAbort(triggerEntity , interactEntity, abortReason) end -- 注意: 不加Condition判断 ,原因:打开UI时满足,关闭如果不满足也是需要能关闭的 UIConditionStr 只控制打开,关闭是无条件的 local interactIndex = 0 for i,data in ipairs(self.InteractDatas) do if data.ID == interactData.ID then interactIndex = i break end end EventSystem.Dispatch(EventID.UI_Interact_Show, false ,interactData ,triggerEntity, entity, interactIndex) end local noCollider = triggerEntity:RemoveInteractEntity(interactEntity) if curCmdOpInteractEntity == interactEntity then if noCollider then triggerInteractComp:SetCmdOpInteractEntity(nil) end self:RefreshColliderEnter(triggerEntity) end -- 如果处在多个交互范围内,则显示下个UI local interactEntity = triggerEntity.components.interact:GetFirstInteractEntity() if not interactEntity then -- 判断是否还在某些交互物范围内 self:SetInteractState(EInteractState.NO_INTERACT) end end -- 刷新在碰撞盒内的交互(如果在交互范围内则显示交互UI) function InteractComponent:RefreshColliderEnter(triggerEntity) local interactList = triggerEntity.components.interact.InteractEntityList for _,nextInteractEntity in ipairs(interactList) do triggerEntity.components.interact.lastTriggerInteractEntity = nextInteractEntity--目的是为了下面的MeetCondition中使用了FirstInteractEntity local nextInteractComp = nextInteractEntity.components.interact local nextInteractDatas = nextInteractComp:GetAllInteractData() local nextColliderIDs = nextInteractComp:GetColliderIDs() for i,colliderID in ipairs(nextColliderIDs) do if ColliderManager.CheckInCollider(colliderID, triggerEntity) then local triggerInteractComp = triggerEntity.components.interact local curCmdOpInteractEntity = triggerInteractComp:GetCmdOpInteractEntity() local interactData = nextInteractDatas[i] local conditionTree = ConditionManager.GetConditionDataTree(interactData.UIConditionStr) if ConditionManager.MeetCondition(triggerEntity, conditionTree) then if curCmdOpInteractEntity == nil then triggerInteractComp:SetCmdOpInteractEntity(nextInteractEntity) curCmdOpInteractEntity = nextInteractEntity end if curCmdOpInteractEntity == nextInteractEntity then EventSystem.Dispatch(EventID.UI_Interact_Show, true, nextInteractDatas[i], triggerEntity, nextInteractEntity, i) end end end end end end function InteractComponent:OnInteractStart(interactData, interactIndex) self:SetInteractingData(interactData, interactIndex) self:SetInteractState(EInteractState.START) end function InteractComponent:OnInteractAbort() self:SetInteractState(EInteractState.ABORT) self:SetInteractingData(nil) end function InteractComponent:OnInteractSucceed() self:SetInteractState(EInteractState.SUCCEED) self:SetInteractingData(nil) end function InteractComponent:IsInteracting() return self.Entity.components.aiBase.CurStateType == LuaConst.StateType.Interact end --给交互物删除一个新的交互功能 function InteractComponent:AddInteract(interactID, pos) if self.InteractDatas == nil then self.InteractDatas = {} self.colliderIDs = {} self.colliderID2InteractDataDic = {} end local interactData = DataSheetManager.InteractData:GetDataByID(interactID) local logicPos = self.Entity.components.move.LogicPos:cloneV2() if pos then logicPos:Reset(pos) end local colliderID = ColliderManager.CreateCircleCollider(logicPos,interactData.InteractRange) local enterCallBack = function(triggerEntity) self:OnInteractColliderEnter(triggerEntity, interactData, self.Entity) end local exitCallBack = function(triggerEntity, exitReason) self:OnInteractColliderExit(triggerEntity, exitReason, interactData, self.Entity) end ColliderManager.AddEnterEvent(colliderID, enterCallBack) ColliderManager.AddExitEvent(colliderID, exitCallBack) table.insert(self.InteractDatas, interactData) table.insert(self.colliderIDs, colliderID) self.colliderID2InteractDataDic[colliderID] = interactData return colliderID, interactData.IsDefaultDisActive end function InteractComponent:DeleteInteract(interactID) local count = 0 if self.InteractDatas then count = #self.InteractDatas for i = count,1,-1 do if self.InteractDatas[i].ID == interactID then table.remove(self.InteractDatas,i) break end end end if self.colliderIDs then count = #self.colliderIDs for i = count,1, -1 do local colliderID = self.colliderIDs[i] local interactData = self:GetInteractDataByColliderID(colliderID) if interactData.ID == interactID then table.remove(self.colliderIDs,i) self.colliderID2InteractDataDic[colliderID] = nil break end end end end return InteractComponent