--副将 local TargetSystem = {} local private = {} local LuaConst=LuaConst local FP=FP local table_insert=table.insert local pairs=pairs local ipairs=ipairs local ChooseType_ignoreBeSkillTarget = LuaConst.ESkillChooseType.NEARESET_IGNORE_BESKILLTARGET local CAMP_NEUTRAL_PEACE = LuaConst.ECampID.NEUTRAL_PEACE local randomIndexList ={} -- 运算需要的table,优化用 --仅用于SearchTargetInList方法 local ESearchTargetInListSearchType = { NEAREST = 1, FAREST = 2, HP_LOWEST = 3, RANDOM = 4, } function TargetSystem.OnLogicUpdate(entity) local components=entity.components local comp_Target = components.target local LogicPos = components.move.LogicPos if comp_Target.Target then if private.CheckClearTarget(entity, comp_Target.Target) then SystemManager.SetTarget(entity,nil) end comp_Target:RefreshTowardsTarget(LogicPos) end comp_Target:RefreshFollowTarget(LogicPos) end function TargetSystem.SetTarget(entity, target) local comp_Target = entity.components.target local comp_Group = entity.components.group local comp_Move = entity.components.move if comp_Group.LeaderEntity then local leader_Comp_Target = comp_Group.LeaderEntity.components.target if leader_Comp_Target.Target == comp_Target.Target then return else target = leader_Comp_Target.Target end end if comp_Target.Target == target then return end if target then comp_Target:SetTarget(target) comp_Target:RefreshTowardsTarget(comp_Move.LogicPos) for _, groupEntity in pairs(comp_Group.GroupEntityList) do local group_Comp_Target = groupEntity.components.target local group_Comp_Move = groupEntity.components.move group_Comp_Target:SetTarget(target) group_Comp_Target:RefreshTowardsTarget(group_Comp_Move.LogicPos) end else comp_Target:ResetTarget() for _, groupEntity in pairs(comp_Group.GroupEntityList) do local group_Comp_Target = groupEntity.components.target group_Comp_Target:ResetTarget() end end end function TargetSystem.SetFollowTarget(entity,target) entity.components.target:SetFollowTarget(target) entity.components.target:RefreshFollowTarget(entity.components.move.LogicPos) end -- ignoreCanNotBeTargetBuff : 会选择身上挂有100047(不可被AI选为Target)Buff的目标 -- noInvincible : 不选择无敌的敌人 -- targetTypeSort : targetTypePriorityGetter为空的情况下按照BOSS>精英>小怪的优先顺序选择, 否则按照在targetTypePriorityGetter返回的priority进行优先顺序选择。 -- targetTypePriorityGetter : 自定义优先级查询器,接收entity作为参数,返回一个 1-3 的整数作为优先级(目前最多只支持3档)。优先级越大越优先被选为目标。 function TargetSystem.OnSearchFollowTarget(entity, camp, disSqr, searchType, monsterType, ignoreCanNotBeTargetBuff, noInvincible, targetTypeSort, targetTypePriorityGetter) local target = TargetSystem.SearchTarget(entity, camp, disSqr, searchType, monsterType, ignoreCanNotBeTargetBuff, noInvincible, targetTypeSort, targetTypePriorityGetter) SystemManager.SetFollowTarget(entity, target) end --返回单位的目标优先级,越大则在查找时越优先被查找 function TargetSystem.GetEntityTargetPriority(entity) local priority = 1 if entity:IsBoss() then priority = 3 elseif entity:IsElite() then priority = 2 end return priority end local _listTemp = {} --[[ 根据资源设置目标 ]] --只会选择[资源没有满]的[英雄] --优先距离近的 function TargetSystem.ChangeTargetByResource(entity, disSqr) local target = nil local compareValue = nil table.clear(_listTemp) for i,entity in ipairs(LogicUpdateManager.EntityList_Sync) do if entity:IsHero() and not LevelManager.CurLevelFunc:IsEntityResAmountReachLimit(entity) then table.insert(_listTemp, entity) end end for i,entity in ipairs(LogicUpdateManager.EntityList_Normal) do if entity:IsHero() and not LevelManager.CurLevelFunc:IsEntityResAmountReachLimit(entity) then table.insert(_listTemp, entity) end end target,compareValue = private.SearchTargetInList(entity, _listTemp, target, compareValue, 1, nil, disSqr, TargetManager.EUnitType.HERO) SystemManager.SetTarget(entity, target) end --[[ 根据令旗数量设置目标(逐鹿中原(大乱斗)玩法使用) ]] --只会选择[令旗没有满]的英雄 --优先距离近的 function TargetSystem.ChangeTargetByFlagAmount(entity, disSqr) local target = nil local compareValue = nil table.clear(_listTemp) for i,entity in ipairs(LogicUpdateManager.EntityList_Sync) do if entity:IsHero() and (LevelManager.CurLevelFunc:GetFlagAmountOfPlayer(entity:GetPlayerID()) <= 0) then table.insert(_listTemp, entity) end end for i,entity in ipairs(LogicUpdateManager.EntityList_Normal) do if entity:IsHero() and (LevelManager.CurLevelFunc:GetFlagAmountOfPlayer(entity:GetPlayerID()) <= 0) then table.insert(_listTemp, entity) end end target,compareValue = private.SearchTargetInList(entity, _listTemp, target, compareValue, 1, nil, disSqr, TargetManager.EUnitType.HERO) SystemManager.SetTarget(entity, target) end local EMPTY_TABLE = {} --camp 参数2 --searchType 参数3 --monsterType 参数4 -- ignoreCanNotBeTargetBuff : 会选择身上挂有100047(不可被AI选为Target)Buff的目标 -- noInvincible : 不选择无敌的敌人 -- targetTypeSort : targetTypePriorityGetter为空的情况下按照BOSS>精英>小怪的优先顺序选择, 否则按照在targetTypePriorityGetter返回的priority进行优先顺序选择。 -- targetTypePriorityGetter : 自定义优先级查询器,接收entity作为参数,返回一个 1-3 的整数作为优先级(目前最多只支持3档)。优先级越大越优先被选为目标。 function TargetSystem.SearchTarget(entity, camp, disSqr, searchType, monsterType, ignoreCanNotBeTargetBuff, noInvincible, targetTypeSort, targetTypePriorityGetter) local target = nil local comp_Group = entity.components.group if comp_Group.LeaderEntity then target = comp_Group.LeaderEntity.components.target.Target else if camp == 3 then --自己 target = entity else local compareValue = nil local list2d = nil if camp == 1 then --敌方 --list2d = TargetManager.Get2DEnemyList(entity) --old --new↓ if entity.CampID ~= CAMP_NEUTRAL_PEACE then --返回非本阵营 且 非中立和平的 --CampManager.Get2DEnitityListExceptCampId直接返回二维数组,所以不用再转换了 list2d = CampManager.Get2DEnitityListExceptCampId(entity.CampID, CAMP_NEUTRAL_PEACE) else list2d = EMPTY_TABLE end --new↑ elseif camp == 2 or camp == 4 then --友方 --list2d = TargetManager.Get2DFriendList(entity) --old list2d = {CampManager.GetEntityListOfCampId(entity.CampID)} end if list2d then --如果开启这个选项,则会按照BOSS>精英>小怪的优先级选目标 if targetTypeSort then local highestPriority if targetTypePriorityGetter then highestPriority = LuaConst.MaxTargetPriority-- hard code 目前写死最多支持4档。现在没有时间优化这个代码,先这么着。1、2、3档都是GetEntityTargetPriority的常规返回值,4作为最优先,给外部自定义的targetTypePriorityGetter使用以做到优先取某类单位 else highestPriority = 3 -- hard code GetEntityTargetPriority是常规优先级Getter,按照boss=3,精英=2,小兵=1的优先级返回,共3档 targetTypePriorityGetter = TargetSystem.GetEntityTargetPriority end for curPriority = highestPriority, 1, -1 do table.clear(_listTemp) for i,list in ipairs(list2d) do for j,entity in ipairs(list) do local priority = targetTypePriorityGetter(entity) or TargetSystem.GetEntityTargetPriority(entity) if priority == curPriority then table.insert(_listTemp, entity) end end end if #_listTemp > 0 then target,compareValue = private.SearchTargetInList(entity, _listTemp, target, compareValue, searchType, camp, disSqr, monsterType, ignoreCanNotBeTargetBuff, noInvincible) end if target then break end end else if searchType == ESearchTargetInListSearchType.RANDOM then table.clear(_listTemp) for i,list in ipairs(list2d) do for j,entity in ipairs(list) do table.insert(_listTemp, entity) end end target,compareValue = private.SearchTargetInList(entity, _listTemp, target, compareValue, searchType, camp, disSqr, monsterType, ignoreCanNotBeTargetBuff, noInvincible) else for i,list in ipairs(list2d) do target,compareValue = private.SearchTargetInList(entity,list,target,compareValue,searchType,camp,disSqr,monsterType,ignoreCanNotBeTargetBuff, noInvincible) end end end end end end return target end --返回二维数组 function TargetSystem.Get2DFriendList(entity) return TargetManager.Get2DFriendList(entity) end --返回二维数组 function TargetSystem.Get2DEnemyList(entity) return TargetManager.Get2DEnemyList(entity) end function private.SearchTargetInList(entity,list,target,compareValue,searchType,camp, disSqr, monsterType, ignoreCanNotBeTargetBuff, noInvincible) if searchType == ESearchTargetInListSearchType.NEAREST then --最近 for key,value in ipairs(list) do if private.Match(entity, value, camp, monsterType, disSqr,ignoreCanNotBeTargetBuff, noInvincible) then local dis = FP.V2.DistanceSqr(entity.components.move.LogicPos, value.components.move.LogicPos) if not compareValue or compareValue > dis then compareValue = dis target = value end end end elseif searchType == ESearchTargetInListSearchType.FAREST then --最远 for key,value in ipairs(list) do if private.Match(entity, value, camp, monsterType, disSqr,ignoreCanNotBeTargetBuff, noInvincible) then local dis = FP.V2.DistanceSqr(entity.components.move.LogicPos, value.components.move.LogicPos) if not compareValue or compareValue < dis then compareValue = dis target = value end end end elseif searchType == ESearchTargetInListSearchType.HP_LOWEST then --血量最低 for key,value in ipairs(list) do if private.Match(entity, value, camp, monsterType, disSqr,ignoreCanNotBeTargetBuff, noInvincible) then local hp = value.components.attr:HitPointPercents() if not compareValue or compareValue > hp then compareValue = hp target = value end end end elseif searchType == ESearchTargetInListSearchType.RANDOM then --随机 for key,value in ipairs(list) do if private.Match(entity, value, camp, monsterType, disSqr,ignoreCanNotBeTargetBuff, noInvincible) then table.insert(randomIndexList,key) end end local count = #randomIndexList local index = LogicRandom.GetIntegerValue(entity, 1, count ,20186) index = randomIndexList[index] target = list[index] table.clearArray(randomIndexList) end return target,compareValue end function TargetSystem.DontBeTargetOfEntity(entity,target) if entity.components.target then if entity.components.target.Target == target then SystemManager.SetTarget(entity,nil) end if entity.components.target.ForceTarget == target then entity.components.target:SetForceTarget(nil) end end end --让entity不再成为目标(包括目标和强制目标) function TargetSystem.DontBeTarget(target) for i,v in ipairs(LogicUpdateManager.EntityList_Sync) do TargetSystem.DontBeTargetOfEntity(v,target) end for i,v in ipairs(LogicUpdateManager.EntityList_Normal) do TargetSystem.DontBeTargetOfEntity(v,target) end end function TargetSystem.OnAttackQuit(entity) entity.components.target:SetJoystickTarget(nil) end function TargetSystem.OnBackground(entity) TargetSystem.DontBeTarget(entity) end function TargetSystem.OnDisActive(entity) TargetSystem.DontBeTarget(entity) end function TargetSystem.OnRevive(entity) entity.components.target:ResetTarget() end function TargetSystem.RefreshTargetOfEntityRelatedTo(entity, relatedTo, relatedToPlayerID) local targetComponent = entity.components.target if targetComponent then if targetComponent.forcePlayerID == relatedToPlayerID then targetComponent:RefreshForceTargetOfForcePlayer() else if targetComponent.Target == relatedTo then SystemManager.SetTarget(entity,nil) end if targetComponent.ForceTarget == relatedTo then targetComponent:SetForceTarget(nil) end end end end function TargetSystem.OnDead(entity) if entity.isHero then -- 目前只有Hero需要这个逻辑,可以添加屏蔽判断 local playerID = entity:GetPlayerID() for i,v in ipairs(LogicUpdateManager.EntityList_Sync) do TargetSystem.RefreshTargetOfEntityRelatedTo(v, entity, playerID) end for i,v in ipairs(LogicUpdateManager.EntityList_Normal) do TargetSystem.RefreshTargetOfEntityRelatedTo(v, entity, playerID) end end end function TargetSystem.OnUnload(entity) if entity.components.target then entity.components.target:ResetTarget() end end function TargetSystem.OnDeadQuit(entity) if entity.components.target then entity.components.target:ResetTarget() end end -- ignoreCanNotBeTargetBuff : 会选择身上挂有100047(不可被AI选为Target)Buff的目标 -- noInvincible : 不选择无敌的敌人 -- targetTypeSort : targetTypePriorityGetter为空的情况下按照BOSS>精英>小怪的优先顺序选择, 否则按照在targetTypePriorityGetter返回的priority进行优先顺序选择。 -- targetTypePriorityGetter : 自定义优先级查询器,接收entity作为参数,返回一个 1-3 的整数作为优先级(目前最多只支持3档)。优先级越大越优先被选为目标。 function TargetSystem.OnSearchTarget(entity, camp, disSqr, searchType, monsterType, ignoreCanNotBeTargetBuff, noInvincible, targetTypeSort, targetTypePriorityGetter) local target local curSkillData = entity.components.skillBase.CurSkillData if curSkillData and curSkillData.MSRecordAimType == LuaConst.EMSRecordAimType.POS_TRACE_ENTITY then if entity.components.record.posTraceEntity then target = entity.components.record.posTraceEntity end else target = TargetSystem.SearchTarget(entity, camp, disSqr, searchType, monsterType, ignoreCanNotBeTargetBuff, noInvincible, targetTypeSort, targetTypePriorityGetter) end SystemManager.SetTarget(entity, target) end -- ignoreCanNotBeTargetBuff : 会选择身上挂有100047(不可被AI选为Target)Buff的目标 -- noInvincible : 不选择无敌的敌人 -- ignoreBeSkillTargetBuff : 为true时会选择身上没有100046(技能自动索敌能被锁到)Buff的目标 function TargetSystem.SearchTargetInCircle(entity,center,radius,ignoreCanNotBeTargetBuff, noInvincible, ignoreBeSkillTargetBuff) local target local curSkillData = entity.components.skillBase.CurSkillData if curSkillData and curSkillData.MSRecordAimType == LuaConst.EMSRecordAimType.POS_TRACE_ENTITY then if entity.components.record.posTraceEntity then target = entity.components.record.posTraceEntity end else target = TargetManager.GetNearestEnemyInCircle(entity,center,radius,ignoreCanNotBeTargetBuff, noInvincible, ignoreBeSkillTargetBuff) end SystemManager.SetTarget(entity, target) end function TargetSystem.SearchPetSkillTargetInCircle(entity, radius) local target = TargetManager.GetNearestEnemyInCircle(entity,entity:GetLogicPos(),radius,false, true, true) return target end -- ignoreCanNotBeTargetBuff : 会选择身上挂有100047(不可被AI选为Target)Buff的目标 -- noInvincible : 不选择无敌的敌人 function TargetSystem.SearchTargetInRect(entity,center,length,width,dir,ignoreCanNotBeTargetBuff, noInvincible) local target local curSkillData = entity.components.skillBase.CurSkillData if curSkillData and curSkillData.MSRecordAimType == LuaConst.EMSRecordAimType.POS_TRACE_ENTITY then if entity.components.record.posTraceEntity then target = entity.components.record.posTraceEntity end else target = TargetManager.GetNearestEnemyInRect(entity,center,length,width,dir,ignoreCanNotBeTargetBuff, noInvincible) end SystemManager.SetTarget(entity, target) end function TargetSystem.SearchEnemyCharAsTargetInCircle(entity, center, radius, characterID, characterType) local target local curSkillData = entity.components.skillBase.CurSkillData if curSkillData and curSkillData.MSRecordAimType == LuaConst.EMSRecordAimType.POS_TRACE_ENTITY then if entity.components.record.posTraceEntity then target = entity.components.record.posTraceEntity end else target = TargetManager.GetNearestEnemyCharInCircle(entity, center, radius, characterID, characterType) end SystemManager.SetTarget(entity, target) end function TargetSystem.SearchEnemyCharAsTargetInRect(entity, center, length, width, dir, characterID, characterType) local target local curSkillData = entity.components.skillBase.CurSkillData if curSkillData and curSkillData.MSRecordAimType == LuaConst.EMSRecordAimType.POS_TRACE_ENTITY then if entity.components.record.posTraceEntity then target = entity.components.record.posTraceEntity end else target = TargetManager.GetNearestEnemyCharInRect(entity, center, length, width, dir, characterID, characterType) end SystemManager.SetTarget(entity, target) end function private.CheckClearTarget(entity, target) local target_components=target.components --当前目标未激活或死亡时,将目标置为空 if not target_components.base.IsActive --未激活 or not target_components.attr:IsAlive() then --死亡 return true end --非玩家,当目标与自己的距离大于警戒范围时,目标置为空 if not entity._logicInitData.NeedSyncInfo then local entity_components=entity.components if entity_components.target.ToTargetDisSqr >= entity_components.base.CurCharacterData.WarnRange then return true end end return false end --region ******************* Skill Target ******************* function TargetSystem.OnSearchTargetBySkill(entity, skillID) local skipSetTarget = false --local skillJoystickData = DataSheetManager.SkillJoyStickData:GetDataByID(skillID) local skillJoystickData = entity.components.skillBase:GetSkillJoystickData(skillID) if skillJoystickData then if skillJoystickData.AimPosType == LuaConst.ESkillJoystickAimPosType.Target then --如果技能的双摇杆类型是锁定目标,就跳过设置目标的代码 skipSetTarget = true end end if not skipSetTarget then SystemManager.SetTarget(entity, private.GetTargetBySkill(entity,skillID)) end end function TargetSystem.GetTargetBySkill(entity, skillID) return private.GetTargetBySkill(entity, skillID) end local lowestHpHeroSearchParam = { campType = LuaConst.ETargetCampType.ENEMY, ignoreCanNotBeTargetBuff = false, ignoreBeSkillTargetBuff = false, noInvincible = true, ignoreEnemyListValid = true, conditionStr = "And(IsHero(0),HpPercentCompare(0,4,0))", regionParams = { shapeType = LuaConst.ERegionShapeType.CIRCLE, shapeNumParams = {}, --实际调用的时候会根据SkillData的配置填充数据 }, sortParams = { sortType = LuaConst.ETargetSortType.HP_LOW, }, priorityGetter = function(entity) if entity:IsHero() then return 2 else return 1 end end, } function private.GetTargetBySkill(entity,skillID) local skillData = entity:GetSkillData(skillID) if skillData.MSRecordAimType == LuaConst.EMSRecordAimType.POS_TRACE_ENTITY then if entity.components.record.posTraceEntity then return entity.components.record.posTraceEntity end end if not skillData or skillData.ChooseRadius <= FP.Const.Zero then return end local forceTarget = entity.components.target.ForceTarget if forceTarget and forceTarget:IsAlive() and forceTarget:IsActive() then return forceTarget end if skillData.ChooseType == LuaConst.ESkillChooseType.LOWEST_HP_HERO_IF_NO_JOYSTICK then lowestHpHeroSearchParam.regionParams.shapeNumParams[1] = skillData.ChooseRadius local target = TargetManager.GetTarget(entity, lowestHpHeroSearchParam) if target then return target end end local moveComponent = entity.components.move local target = nil local searchTable = {} local enemyList2d = TargetManager.Get2DEnemyList(entity) for i,list in ipairs(enemyList2d) do private.SetSkillSearchTable(entity,list,skillData,searchTable) end --选取距离最近的 -- local min = nil -- for key,value in pairs(searchTable) do -- local dis = FP.V2.DistanceSqr(moveComponent.LogicPos, value.components.move.LogicPos) -- --print("id", value._logicInitData.EntityID, "dis", dis) -- if not min or min > dis then -- min = dis -- target = value -- --print("change") -- end -- end local highestPriority = entity.components.target.SkillHighestPriorityTarget if highestPriority then for i,searchEntity in ipairs(searchTable) do if highestPriority == searchEntity then return searchEntity end end end return private.GetNearestEntityInList(moveComponent.LogicPos,searchTable) end function private.GetNearestEntityInList(center,list) local target = nil local min = nil for i,entity in ipairs(list) do local dis = FP.V2.DistanceSqr(center, entity.components.move.LogicPos) --print("id", entity._logicInitData.EntityID, "dis", dis) if not min or min > dis then min = dis target = entity --print("change") end end return target end --预测entity释放skillID的时候瞄准的位置的坐标 --不会修改任何战斗数据,可以给战斗外部的模块使用,比如双摇杆UI function TargetSystem.PredictSkillAimPos(entity,skillID) local pos = nil local target = private.GetTargetBySkill(entity,skillID) if target then pos = target.components.move.LogicPos:cloneV2() end return pos end function private.GetEntitiesInCircle(pos,radius) local entities = {} local entityDic = BattleDataGetter.GetEntityDic() for k,entity in pairs(entityDic) do if private.MatchDis(pos,entity,radius) then table_insert(entities,entity) end end return entities end function private.SetSkillSearchTable(entity,list,skillData,searchTable) local chooseRadius = skillData.ChooseRadius * skillData.ChooseRadius local components=entity.components local comp_Move = components.move local visualFieldComp = components.visualField local ignoreBeSkillTargetBuff = (components.autoFight:IsAutoFight() and (not components.aiBase.isBreakByInput)) or skillData.ChooseType == ChooseType_ignoreBeSkillTarget local noInvincible = true --有摇杆输入时(只有手操角色才有摇杆输入) if entity._logicInitData.NeedSyncInfo and comp_Move.VirtualMoveDir ~= FP.Const.Vector2_Zero then local inputCorrect = LevelManager.ShouldKeepSyncLevel() and skillData.InputCorrectPVP or skillData.InputCorrectPVE for key,tempEntity in pairs(list) do if not components.target:IsIgnoreEnemey(tempEntity) and LevelManager.CurLevelFunc:CanSeeEntity(entity, tempEntity) then if private.MatchStateSkill(tempEntity,ignoreBeSkillTargetBuff,noInvincible) and private.MatchDis(components.move.LogicPos, tempEntity, chooseRadius) and private.MatchAngle(comp_Move.LogicPos, comp_Move.VirtualMoveDir, tempEntity, inputCorrect) then table_insert(searchTable, tempEntity) end end end else --无遥感输入时 local hasEntity = false -- 0 .先选相机的锁定 local highestPriority = components.target.SkillHighestPriorityTarget if highestPriority then if not components.target:IsIgnoreEnemey(highestPriority) and LevelManager.CurLevelFunc:CanSeeEntity(entity, highestPriority) then if private.MatchStateSkill(highestPriority,ignoreBeSkillTargetBuff,noInvincible) and private.MatchDis(comp_Move.LogicPos, highestPriority, chooseRadius) then --print("add", highestPriority._logicInitData.EntityID) table_insert(searchTable, highestPriority) hasEntity = true end end end --1 .选择身前180度范围内的 特定怪 for key,tempEntity in pairs(list) do local angleLimit = FP.newV1(90) if not components.target:IsIgnoreEnemey(tempEntity) and LevelManager.CurLevelFunc:CanSeeEntity(entity, tempEntity) then if private.MatchStateSkill(tempEntity,ignoreBeSkillTargetBuff,noInvincible) and private.MatchDis(comp_Move.LogicPos, tempEntity, chooseRadius) and private.MatchAngle(comp_Move.LogicPos, comp_Move.LogicRotateDir, tempEntity, angleLimit) then --print("add", tempEntity._logicInitData.EntityID) table_insert(searchTable, tempEntity) hasEntity = true end end end --2.若无,则从360度范围内选择 ,特定怪 if not hasEntity then for key,tempEntity in pairs(list) do if not components.target:IsIgnoreEnemey(tempEntity) and LevelManager.CurLevelFunc:CanSeeEntity(entity, tempEntity) then if private.MatchStateSkill(tempEntity,ignoreBeSkillTargetBuff,noInvincible) and private.MatchDis(components.move.LogicPos, tempEntity, chooseRadius) then --print("add", tempEntity._logicInitData.EntityID) table_insert(searchTable, tempEntity) hasEntity = true end end end end end end --endregion Skill Target --region ******************* BuffSkill Target ******************* function TargetSystem.SearchTargetByBuffSkill(entity, buffSkillData) return private.GetTargetByBuffSkill(entity,buffSkillData) end function private.GetTargetByBuffSkill(entity,buffSkillData) if not buffSkillData or buffSkillData.ChooseRadius <= FP.Const.Zero then return end local forceTarget = entity.components.target.ForceTarget if forceTarget and forceTarget:IsAlive() and forceTarget:IsActive() then return forceTarget end if buffSkillData.ChooseType == LuaConst.ESkillChooseType.LOWEST_HP_HERO_IF_NO_JOYSTICK then lowestHpHeroSearchParam.regionParams.shapeNumParams[1] = buffSkillData.ChooseRadius local target = TargetManager.GetTarget(entity, lowestHpHeroSearchParam) if target then return target end end local moveComponent = entity.components.move local target = nil local searchTable = {} local enemyList2d = TargetManager.Get2DEnemyList(entity) for i,list in ipairs(enemyList2d) do private.SetBuffSkillSearchTable(entity,list,buffSkillData,searchTable) end local highestPriority = entity.components.target.SkillHighestPriorityTarget if highestPriority then for i,searchEntity in ipairs(searchTable) do if highestPriority == searchEntity then return searchEntity end end end return private.GetNearestEntityInList(moveComponent.LogicPos,searchTable) end function private.SetBuffSkillSearchTable(entity,list,buffSkillData,searchTable) local chooseRadius = buffSkillData.ChooseRadius * buffSkillData.ChooseRadius local components=entity.components local comp_Move = components.move local visualFieldComp = components.visualField local ignoreBeSkillTargetBuff = components.autoFight:IsAutoFight() and (not components.aiBase.isBreakByInput) local noInvincible = true --有方向遥感输入时(只有手操角色才有遥感输入) if entity._logicInitData.NeedSyncInfo and comp_Move.VirtualMoveDir ~= FP.Const.Vector2_Zero then local inputCorrect = LevelManager.ShouldKeepSyncLevel() and buffSkillData.InputCorrectPVP or buffSkillData.InputCorrectPVE for key,tempEntity in pairs(list) do -- pairs safe if not components.target:IsIgnoreEnemey(tempEntity) and LevelManager.CurLevelFunc:CanSeeEntity(entity, tempEntity) then if private.MatchStateSkill(tempEntity,ignoreBeSkillTargetBuff,noInvincible) and private.MatchDis(comp_Move.LogicPos, tempEntity, chooseRadius) and private.MatchAngle(comp_Move.LogicPos, comp_Move.VirtualMoveDir, tempEntity, inputCorrect) then table_insert(searchTable, tempEntity) end end end else --无方向遥感输入时 local hasEntity = false -- 0 .先选相机的锁定 local highestPriority = components.target.SkillHighestPriorityTarget if highestPriority then if not components.target:IsIgnoreEnemey(highestPriority) and LevelManager.CurLevelFunc:CanSeeEntity(entity, highestPriority) then if private.MatchStateSkill(highestPriority,ignoreBeSkillTargetBuff,noInvincible) and private.MatchDis(comp_Move.LogicPos, highestPriority, chooseRadius) then --print("add", highestPriority._logicInitData.EntityID) table_insert(searchTable, highestPriority) hasEntity = true end end end --1 .选择身前180度范围内的 特定怪 for key,tempEntity in pairs(list) do local angleLimit = FP.newV1(90) if not components.target:IsIgnoreEnemey(tempEntity) and LevelManager.CurLevelFunc:CanSeeEntity(entity, tempEntity) then if private.MatchStateSkill(tempEntity,ignoreBeSkillTargetBuff,noInvincible) and private.MatchDis(comp_Move.LogicPos, tempEntity, chooseRadius) and private.MatchAngle(comp_Move.LogicPos, comp_Move.LogicRotateDir, tempEntity, angleLimit) then --print("add", tempEntity._logicInitData.EntityID) table_insert(searchTable, tempEntity) hasEntity = true end end end --2.若无,则从360度范围内选择 ,特定怪 if not hasEntity then for key,tempEntity in pairs(list) do if not components.target:IsIgnoreEnemey(tempEntity) and LevelManager.CurLevelFunc:CanSeeEntity(entity, tempEntity) then if private.MatchStateSkill(tempEntity,ignoreBeSkillTargetBuff,noInvincible) and private.MatchDis(components.move.LogicPos, tempEntity, chooseRadius) then --print("add", tempEntity._logicInitData.EntityID) table_insert(searchTable, tempEntity) hasEntity = true end end end end end end --预测entity释放buffSkillID的时候瞄准的位置的坐标 --不会修改任何战斗数据,可以给战斗外部的模块使用,比如双摇杆UI function TargetSystem.PredictBuffSkillAimPos(entity,buffSkillData) local pos = nil local target = private.GetTargetByBuffSkill(entity,buffSkillData) if target then pos = target.components.move.LogicPos:cloneV2() end return pos end --endregion BuffSkill Target --region ******************* Tracker Target ******************* function TargetSystem.OnSearchTrackerTarget(missile) local limitAngle = FP.newV1(missile.MissileData.AimAngle) if limitAngle <= FP.Const.Zero then return nil end local checkDis = missile.MissileData.AimRadius > 0 local disSqr = FP.newV1(missile.MissileData.AimRadius * missile.MissileData.AimRadius) local searchType = missile.MissileData.AimTactics local target = nil local entity = missile.Attacker local aimType = missile.MissileData.AimType local searchTable = {} if aimType == LuaConst.MissileImpactType.Self then --自己 table_insert(searchTable, missile.Attacker) elseif aimType == LuaConst.MissileImpactType.Enemy then --敌方 --new↓ local list2d = TargetManager.Get2DEnemyList(missile.Attacker) for i,list in ipairs(list2d) do private.SetTrackSearchTable(entity,list,disSqr,limitAngle,checkDis,searchTable,missile, false, aimType) end --new↑ elseif aimType == LuaConst.MissileImpactType.Friend then --自己 --new↓ local list2d = TargetManager.Get2DFriendList(missile.Attacker) for i,list in ipairs(list2d) do private.SetTrackSearchTable(entity,list,disSqr,limitAngle,checkDis,searchTable,missile, false, aimType) end --new↑ elseif aimType == LuaConst.MissileImpactType.EnemyAndFriend then --敌方加友方(不包括自己) local list2d = TargetManager.Get2DEnemyList(missile.Attacker) for i,list in ipairs(list2d) do private.SetTrackSearchTable(entity, list, disSqr, limitAngle, checkDis, searchTable, missile, false, aimType) end list2d = TargetManager.Get2DFriendList(missile.Attacker) for i,list in ipairs(list2d) do private.SetTrackSearchTable(entity, list, disSqr, limitAngle, checkDis, searchTable, missile, true, aimType) end elseif aimType == LuaConst.MissileImpactType.NoPeace then -- 非中立和平(敌方+友方+自己) local list2d = TargetManager.Get2DNoPeaceList(missile.Attacker) for i,list in ipairs(list2d) do private.SetTrackSearchTable(entity,list,disSqr,limitAngle,checkDis,searchTable,missile, false, aimType) end end if searchType == 1 then --距离发射者最近 local min = nil for key,value in pairs(searchTable) do local dis = FP.V2.DistanceSqr(entity.components.move.LogicPos, value.components.move.LogicPos) if not min or min > dis then min = dis target = value end end elseif searchType == 2 then --最远 local max = nil for key,value in pairs(searchTable) do local dis = FP.V2.DistanceSqr(entity.components.move.LogicPos, value.components.move.LogicPos) if not max or max < dis then max = dis target = value end end elseif searchType == 3 then --血量最高 local hpMax = nil for key,value in pairs(searchTable) do local hp = value.components.attr:HitPointPercents() if not hpMax or hpMax < hp then hpMax = hp target = value end end elseif searchType == 4 then --血量最低 local hpMin = nil for key,value in pairs(searchTable) do local hp = value.components.attr:HitPointPercents() if not hpMin or hpMin > hp then hpMin = hp target = value end end elseif searchType == 5 then --随机 local index = LogicRandom.GetIntegerValue(entity, 1, #searchTable ,12) target = searchTable[index] elseif searchType == 6 then --距离子弹最近 local min = nil for key,value in pairs(searchTable) do local dis = FP.V2.DistanceSqr(missile.Pos, value.components.move.LogicPos) if not min or min > dis then min = dis target = value end end end return target end function private.SetTrackSearchTable(entity,list,disSqr, limitAngle, checkDis, searchTable, missile, excludeSelf, aimType) for key, value in pairs(list) do if (not excludeSelf or value ~= entity) and ( --这一大块主要是为了排除掉 IsIgnoreEnemey 的单位↓ (aimType ~= LuaConst.MissileImpactType.Enemy and aimType ~= LuaConst.MissileImpactType.EnemyAndFriend and aimType ~= LuaConst.MissileImpactType.NoPeace) or ( entity._logicInitData.EntityCampID == value._logicInitData.EntityCampID or not entity.components.target:IsIgnoreEnemey(value) ) --这一大块主要是为了排除掉 IsIgnoreEnemey 的单位↑ ) and LevelManager.CurLevelFunc:CanSeeEntity(entity, value) then if private.MatchTrackerCondition(entity.components.move.LogicPos, entity.components.move.LogicRotateDir, value, disSqr, limitAngle, checkDis,missile) then table_insert(searchTable, value) end end end end function private.MatchTrackerCondition(pos, dir, tempEntity, disSqr, limitAngle, checkDis,missile) if checkDis then return private.MatchState(tempEntity) and private.MatchDis(pos, tempEntity, disSqr) and private.MatchAngle(pos, dir, tempEntity, limitAngle) and private.MatchConditionStr(tempEntity,missile.MissileData.AimConditionStr,missile) else return private.MatchState(tempEntity) and private.MatchAngle(pos, dir, tempEntity, limitAngle) and private.MatchConditionStr(tempEntity,missile.MissileData.AimConditionStr,missile) end end --endregion Tracker Target --region ******************* Match Function ******************* function private.Match(entity, tempEntity, camp, monsterType, disSqr,ignoreCanNotBeTargetBuff, noInvincible) return TargetManager.Match(entity, tempEntity, camp, monsterType, disSqr,ignoreCanNotBeTargetBuff, noInvincible) end function private.MatchCamp(entity, tempEntity, camp) return TargetManager.MatchCamp(entity,tempEntity,camp) end function private.MatchState(tempEntity,ignoreCanNotBeTargetBuff,noInvincible) -- if not ignoreCanNotBeTargetBuff and tempEntity.components.buff:GetBuffUpdateData(LuaConst.SpecialBuffs.CanNotBeTarget) then -- return false -- end -- if tempEntity.components.buff:GetBuffUpdateData(LuaConst.SpecialBuffs.CantBeTrigger) then -- return false -- end -- if not tempEntity.components.base.IsActive then --未激活 -- return false -- end -- if not tempEntity.components.attr:IsAlive() then --未激活 -- return false -- end -- return true return TargetManager.MatchState(tempEntity,ignoreCanNotBeTargetBuff,noInvincible) end function private.MatchStateSkill(tempEntity,ignoreBeSkillTargetBuff,noInvincible) -- if not ignoreBeSkillTargetBuff and not tempEntity.components.buff:GetBuffUpdateData(LuaConst.SpecialBuffs.BeSkillTarget) then -- return false -- end -- if tempEntity.components.buff:GetBuffUpdateData(LuaConst.SpecialBuffs.CantBeTrigger) then -- return false -- end -- if not tempEntity.components.base.IsActive then --未激活 -- return false -- end -- if not tempEntity.components.attr:IsAlive() then --未激活 -- return false -- end -- return true return TargetManager.MatchStateSkill(tempEntity,ignoreBeSkillTargetBuff,noInvincible) end function private.IsMonsterType(unitType) return TargetManager.IsMonsterType(unitType) end function private.MatchSearchUnitType(entity,tempEntity, unitType) return TargetManager.MatchSearchUnitType(entity,tempEntity,unitType) end --radius : 限定距离,跟width和height互斥,radius优先生效 --length、width :限定以center为中心的矩形内,跟radius互斥,radius优先生效 function TargetSystem.SearchEnemyMonsterOfLevelItem(entity, itemID, center, radius, length, width, dir) local levelItemData = LevelItemManager.GetItemDataByID(itemID) if levelItemData then for i,target in ipairs(LogicUpdateManager.EntityList_Normal) do if target._logicInitData.OriginBornItemID == itemID then if target:IsAlive() then local buffComp = target.components.buff if CampManager.IsEnemyEntity(entity, target) then if not buffComp:GetBuffUpdateData(LuaConst.SpecialBuffs.CanNotBeTarget) and not buffComp:GetBuffUpdateData(LuaConst.SpecialBuffs.CantBeTrigger) and not buffComp.HasBuffOfInvicibleGroup then if radius then if not FP.V2.IsDistanceGreater(center, target:GetLogicPos(), radius) then SystemManager.SetTarget(entity, target) break end elseif length and width then if FP.V2.IsInRectRange(center, target:GetLogicPos(), dir, length, width) then SystemManager.SetTarget(entity, target) break end else SystemManager.SetTarget(entity, target) break end end end end end end end end function private.MatchAngle(pos, dir, tempEntity, limitAngle) local toTarget = tempEntity.components.move.LogicPos - pos toTarget:Normalize() local angle = FP.V2.Angle(toTarget, dir) FP.releaseV2(toTarget) return angle < limitAngle end function private.MatchDis(pos, tempEntity, disSqr) --return not FP.V2.IsDistanceSqrGreater(pos, tempEntity.components.move.LogicPos, disSqr) return TargetManager.MatchDis(pos, tempEntity, disSqr) end function private.MatchConditionStr(entity, conditionStr, missile, buffObject) local conditionTree = ConditionManager.GetConditionDataTree(conditionStr) if ConditionManager.MeetCondition(entity, conditionTree,missile, buffObject) then return true else return false end end --endregion Match Function return TargetSystem