--目标管理器,提供目标查询接口 local TargetManager = {} local FP=FP local LuaConst=LuaConst local _tempV1 = FP.newV1(0) local _tempV1_2 = FP.newV1(0) local _tempV1_3 = FP.newV1(0) local _tempVec2 = FP.newV2(0, 0) local _tempMinDis = FP.newV1(0) local _tempTargetDis = FP.newV1(0) -- 作为AI编辑器配置数据的解释规则 -- local _EUnitType = { -- ANY = 0, -- HERO = 1, -- NPC = 2, -- SUMMON_MASTER = 3, --召唤物的主人 -- MONSTER_START = 101, -- MONSTER_END = 199, -- } local _EUnitType = LuaConst.ESearchTargetCharacterType local ETargetCampType = LuaConst.ETargetCampType local ERegionShapeType = LuaConst.ERegionShapeType local ERegionCenterType = LuaConst.ERegionCenterType local ETargetSortType = LuaConst.ETargetSortType local EDistType = LuaConst.EDistType TargetManager.EUnitType = _EUnitType local VisualFieldSystem = require "Battle/Logic/Entity/System/VisualFieldSystem" local function Get2DListCount(list2d) local count = 0 if list2d then for i,list in ipairs(list2d) do count = count + #list end end return count end --会包含entity自身 function TargetManager.Get2DFriendList(entity) --CampManager.GetEntityListOfCampId范围一维数组,需要转换为二维数组 return {CampManager.GetEntityListOfCampId(entity:GetCampID())} end --会包含entity自身 function TargetManager.Get2DFriendListCopy(entity) --CampManager.GetEntityListOfCampId范围一维数组,需要转换为二维数组 return {CampManager.GetEntityListCopyOfCampId(entity:GetCampID())} end --会包含entity自身, 返回一维数组,返回的是副本可以自由修改 function TargetManager.GetFriendListCopy(entity) local result = {} local friends = CampManager.GetEntityListOfCampId(entity:GetCampID()) for i,v in ipairs(friends) do table.insert(result, v) end return result end function TargetManager.GetEntityListCopyOfAll(entity) local result = {} for i,v in ipairs(LogicUpdateManager.EntityList_Normal) do result[#result + 1] = v end for i,v in ipairs(LogicUpdateManager.EntityList_Sync) do result[#result + 1] = v end return result end --不会包含entity自身,返回二维数组 function TargetManager.Get2DFriendListCopyExcludeSelf(entity) local result = {{}} local friends = CampManager.GetEntityListOfCampId(entity:GetCampID()) for i,v in ipairs(friends) do if v ~= entity then table.insert(result[1], v) end end end --不会包含entity,返回一维数组,返回的是副本可以自由修改 function TargetManager.GetFriendListCopyExcludeSelf(entity) local result = {} local friends = CampManager.GetEntityListOfCampId(entity:GetCampID()) for i,v in ipairs(friends) do if v ~= entity then table.insert(result, v) end end return result end function TargetManager.GetEntityCountInCircleOfCamp(pos,radius,campId) local entityList = CampManager.GetEntityListOfCampId(campId) local count = 0 if entityList then for i,entity in ipairs(entityList) do _tempV1:Reset(radius):Mul(radius) if not FP.V2.IsDistanceSqrGreater(pos, entity:GetLogicPos(), FP.tonumberV1(_tempV1)) then count = count + 1 end end end return count end local EMPTY_TABLE = {} --返回二维数组,只考虑阵营,阵营不同的就会认为是enemy --返回的是原始数据,禁止修改! function TargetManager.Get2DEnemyList(entity) if entity.CampID ~= LuaConst.ECampID.NEUTRAL_PEACE then --返回非本阵营 且 非中立和平的 --CampManager.Get2DEnitityListExceptCampId直接返回二维数组,所以不用再转换了 return CampManager.Get2DEnitityListExceptCampId(entity.CampID, LuaConst.ECampID.NEUTRAL_PEACE) else return EMPTY_TABLE end end --跟TargetManager.Get2DEnemyList功能一致,但结果返回副本,可以自由修改 function TargetManager.Get2DEnemyListCopy(entity) local copy = {} local origin2DList = TargetManager.Get2DEnemyList(entity) for i,list in ipairs(origin2DList) do local listCopy = {} for j,_entity in ipairs(list) do table.insert(listCopy, _entity) end table.insert(copy, listCopy) end return copy end --返回一维数组,结果返回副本,可以自由修改 function TargetManager.GetEnemyListCopy(entity) local result = {} local origin2DList = TargetManager.Get2DEnemyList(entity) for i,list in ipairs(origin2DList) do for j,_entity in ipairs(list) do result[#result + 1] = _entity end end return result end --返回非中立和平的阵营的单位的二维数组 function TargetManager.Get2DNoPeaceList() return CampManager.Get2DNoPeaceList() end function TargetManager.Get2DNoPeaceListCopy() local origin = CampManager.Get2DNoPeaceList() local index = 1 for k,list in pairs(origin) do origin[index] = {} for i,entity in ipairs(list) do origin[index][i] = entity end index = index + 1 end return origin --origin本身就是副本,只是内部的元素不是副本 end --返回非本阵营的单位,包括中立和平 function TargetManager.Get2DNoFriendList(entity) return CampManager.Get2DEnitityListExceptCampId(entity:GetCampID()) end local _tempList2D = {} function TargetManager.GetNearestHero(center) local entityListDic = LevelPlayerManager.GetHeroEntities() table.clear(_tempList2D) for i,playerID in ipairs(LevelPlayerManager.PlayerIDList) do local entityList = entityListDic[playerID] table.insert(_tempList2D, entityList) end return TargetManager.GetNearestTargetIn2DList(center, _tempList2D, false, false ,true) end function TargetManager.GetNearestEnemyOfTeam(entity, teamId) local target = nil local entities = LevelPlayerManager.GetAliveAndActiveEntitiesOfTeam(teamId) if entities and entities[1] then local minDistanceSqr = FP.V2.DistanceSqr(entity:GetLogicPos(), entities[1]:GetLogicPos()) target = entities[1] for i=2,#entities do local _entity = entities[i] local distanceSqr = FP.V2.DistanceSqr(entity:GetLogicPos(), _entity:GetLogicPos()) if distanceSqr < minDistanceSqr then target = _entity minDistanceSqr = distanceSqr end end end return target end --返回fanshapeDir一定角度内的敌人的二维数组, fanshapeDir为nil时以entity面向为法线 --angle为角度范围 function TargetManager.GetEnemy2DListWithinAngle(entity, angle, ignoreCanNotBeTargetBuff, noInvincible, pos, fanshapeDir) local enemyList2d = TargetManager.Get2DEnemyListCopy(entity) local halfAngle = FP.newV1(angle):Div(2) local bigSideAngle = FP.newV1(360):Sub(halfAngle) local maxBigSideAngle = FP.newV1(360) pos = pos or entity:GetLogicPos() fanshapeDir = fanshapeDir or entity.components.move.LogicRotateDir for i,enemyList in ipairs(enemyList2d) do for j=#enemyList, 1, -1 do local enemy = enemyList[j] _tempVec2:Reset(enemy:GetLogicPos()):Sub(pos):Normalize() --endDir if not FP.V2.AngleRangeCheckByDir(fanshapeDir, _tempVec2, FP.Const.Zero, halfAngle) and not FP.V2.AngleRangeCheckByDir(fanshapeDir, _tempVec2, bigSideAngle, maxBigSideAngle) then --这里就是得用and table.remove(enemyList, j) end end end return enemyList2d end --返回fanshapeDir为法线的扇形内的敌人的二维数组, fanshapeDir为nil时以entity面向为法线 --angle为角度范围 function TargetManager.GetEnemy2DListInFanshape(entity, angle, ignoreCanNotBeTargetBuff, noInvincible, pos, fanshapeDir, radius) local enemyList2d = TargetManager.GetEnemy2DListWithinAngle(entity, angle, ignoreCanNotBeTargetBuff, noInvincible, pos, fanshapeDir) local radiusSqr = _tempV1:Reset(radius):Mul(radius) for i,enemyList in ipairs(enemyList2d) do for j=#enemyList, 1, -1 do local enemy = enemyList[j] if not TargetManager.MatchDis(pos or entity:GetLogicPos(), enemy, radiusSqr) then table.remove(enemyList, j) end end end return enemyList2d end local _tempV2_GetNearestEnemyInFanShape = FP.newV2(0, 0) --返回离pos最近的,且位于扇形内的entity的敌人 --如果不传pos,则使用entiy的pos --如果不传fanshapeDir,则使用entity的面向 --fanshapeAngle必须传0-360的值 -- ignoreCanNotBeTargetBuff : 会选择身上挂有100047(不可被AI选为Target)Buff的目标 -- noInvincible : 不选择无敌的敌人 -- ignoreBeSkillTargetBuff : 为true时会选择身上没有100046(技能自动索敌能被锁到)Buff的目标 -- isClosestToDir : 是否选取最靠近entity位置跟目标点连线的单位(默认为否,此时会选取离 【distCompareCenter or pos or entity:GetLogicPos()】这个表达式表达的pos最近的单位) function TargetManager.GetNearestEnemyInFanShape(entity, radius, fanshapeAngle, ignoreCanNotBeTargetBuff, noInvincible, pos, fanshapeDir, distCompareCenter, ignoreBeSkillTargetBuff, distType) local enemyList2d = TargetManager.GetEnemy2DListInFanshape(entity, fanshapeAngle,ignoreCanNotBeTargetBuff, noInvincible, pos, fanshapeDir, radius) local targetPos = distCompareCenter or pos or entity:GetLogicPos() local targetDir if distType == LuaConst.EDistType.POINT_TO_LINE or distType == LuaConst.EDistType.LINE_ANGLE then _tempV2_GetNearestEnemyInFanShape:Reset(targetPos):Sub(entity:GetLogicPos()) targetDir = _tempV2_GetNearestEnemyInFanShape if targetDir == FP.Const.Vector2_Zero then distType = LuaConst.EDistType.DEFAULT_POINT_TO_POINT --如果方向向量为0向量,则点到直线的距离没有意义, 改为使用默认的点到点的距离 end end if distType == LuaConst.EDistType.POINT_TO_LINE then return TargetManager.GetNearestTargetIn2DList(entity:GetLogicPos(), enemyList2d, ignoreCanNotBeTargetBuff, noInvincible, ignoreBeSkillTargetBuff, targetDir, distType, entity) elseif distType == LuaConst.EDistType.LINE_ANGLE then return TargetManager.GetNearestTargetIn2DList(entity:GetLogicPos(), enemyList2d, ignoreCanNotBeTargetBuff, noInvincible, ignoreBeSkillTargetBuff, targetDir, distType, entity) else return TargetManager.GetNearestTargetIn2DList(targetPos, enemyList2d, ignoreCanNotBeTargetBuff, noInvincible, ignoreBeSkillTargetBuff, nil, nil, entity) end end --返回离pos距离radius以内的最近的entity的敌人 pos可以自由设置,不一定是entity的LogicPos -- ignoreCanNotBeTargetBuff : 会选择身上挂有100047(不可被AI选为Target)Buff的目标 -- noInvincible : 不选择无敌的敌人 -- ignoreBeSkillTargetBuff : 为true时会选择身上没有100046(技能自动索敌能被锁到)Buff的目标 function TargetManager.GetNearestEnemyInCircle(entity, pos, radius, ignoreCanNotBeTargetBuff, noInvincible, ignoreBeSkillTargetBuff) local enemyList2d = TargetManager.Get2DEnemyList(entity) local entityTemp = TargetManager.GetNearestTargetIn2DList(pos, enemyList2d, ignoreCanNotBeTargetBuff, noInvincible, ignoreBeSkillTargetBuff, nil, nil, entity) local radiusSqr = _tempV1:Reset(radius):Mul(radius) if entityTemp and TargetManager.MatchDis(pos,entityTemp,radiusSqr) then return entityTemp end return nil end --返回离pos距离radius以内的最近的,匹配characterID和characterType的,entity的敌人 function TargetManager.GetNearestEnemyCharInCircle(entity, center, radius, characterID, characterType) local enemyList2d = TargetManager.Get2DEnemyList(entity) local entityTemp = TargetManager.GetNearestCharacterIn2DList(center, enemyList2d, characterID, characterType) local radiusSqr = _tempV1:Reset(radius):Mul(radius) if entityTemp and TargetManager.MatchDis(center, entityTemp, radiusSqr) then return entityTemp end return nil end function TargetManager.GetNearestEnemyInRect(entity,center,length,width,dir,ignoreCanNotBeTargetBuff,noInvincible) local result local enemyList2d = TargetManager.Get2DEnemyList(entity) local minDistSqr = FP.newV1(9999999) local distSqr for i,entityList in ipairs(enemyList2d) do for j, entityTemp in ipairs(entityList) do if TargetManager.MatchState(entityTemp,ignoreCanNotBeTargetBuff,noInvincible) and LevelManager.CurLevelFunc:CanSeeEntity(entity, entityTemp) then if FP.V2.IsInRectRange(entityTemp:GetLogicPos(),center,dir,length,width) then distSqr = entityTemp:GetLogicPos():DistanceSqr(entity:GetLogicPos()) if minDistSqr > distSqr then minDistSqr:Reset(distSqr) result = entityTemp end end end end end return result end function TargetManager.GetNearestEnemyCharInRect(entity, center, length, width, dir, characterID, characterType) local enemyList2d = TargetManager.Get2DEnemyList(entity) return TargetManager.GetNearestCharacterIn2DListWithinRect(entity, enemyList2d, center, length, width, dir, characterID, characterType) end function TargetManager.GetFriendCountInCircle(entity,pos,radius,searchTargetCharacterType,shouldAlive) local friendList2d = TargetManager.Get2DFriendList(entity) local radiusSqr = _tempV1:Reset(radius):Mul(radius) local count = 0 if friendList2d then for i,list in ipairs(friendList2d) do for j, entityTemp in ipairs(list) do if TargetManager.MatchDis(pos, entityTemp,radiusSqr) then if searchTargetCharacterType == nil or TargetManager.MatchSearchUnitType(entity, entityTemp, searchTargetCharacterType) then if not shouldAlive or (entityTemp:IsAlive() and (entityTemp:IsActive() or entityTemp.components.drive and entityTemp.components.drive.DriveEntity)) then count = count + 1 end end end end end end return count end function TargetManager.GetEnemyCountInCircle(entity,pos,radius,searchTargetCharacterType,shouldAlive) local enemyList2d = TargetManager.Get2DEnemyList(entity) local radiusSqr = _tempV1:Reset(radius):Mul(radius) local count = 0 if enemyList2d then for i,list in ipairs(enemyList2d) do for j, entityTemp in ipairs(list) do if TargetManager.MatchDis(pos, entityTemp,radiusSqr) then if searchTargetCharacterType == nil or TargetManager.MatchSearchUnitType(entity, entityTemp, searchTargetCharacterType) then if not shouldAlive or (entityTemp:IsAlive() and (entityTemp:IsActive() or entityTemp.components.drive and entityTemp.components.drive.DriveEntity)) then count = count + 1 end end end end end end return count end local _tempJoystickDir = FP.newV2(0, 0) local _tempJoystickAimPos = FP.newV2(0, 0) local _tempGetTargetsByJoystick = { campType = LuaConst.ETargetCampType.ENEMY, regionParams = { pos = FP.newV2(0,0), vector2Param1 = FP.newV2(0, 0), shapeNumParams = {}, }, sortParams = { vector2Param1 = FP.newV2(0, 0), vector2Param2 = FP.newV2(0, 0), }, } -- joystickPos:双摇杆准星的世界坐标位置 function TargetManager.GetTargetByJoystick(entity, skillJoyStickData, joystickPos, count, ignoreBeSkillTargetBuff, sortType) count = count or 1 local result if skillJoyStickData.ShapeType == LuaConst.ESkillJoystickShapeType.CIRCLE then if skillJoyStickData.UEType == LuaConst.ESkillJoystickUEType.JOYSTICK_DIR then _tempJoystickDir:Reset(joystickPos) _tempJoystickDir:Sub(entity:GetLogicPos()) _tempJoystickDir:Normalize() _tempJoystickAimPos:Reset(_tempJoystickDir) _tempJoystickAimPos:Mul(skillJoyStickData.ShapeParam1) _tempJoystickAimPos:Add(entity:GetLogicPos()) else _tempJoystickAimPos:Reset(joystickPos) end if count == 1 then result = TargetManager.GetNearestEnemyInCircle( entity, _tempJoystickAimPos, skillJoyStickData.ShapeParam1, nil, nil, ignoreBeSkillTargetBuff) else --必须全量设置所有9个参数(跟下面的设置数量保持一致),否则可能引发不一致 _tempGetTargetsByJoystick.ignoreBeSkillTargetBuff = ignoreBeSkillTargetBuff _tempGetTargetsByJoystick.regionParams.shapeType = LuaConst.ERegionShapeType.CIRCLE _tempGetTargetsByJoystick.regionParams.pos:Reset(_tempJoystickAimPos) _tempGetTargetsByJoystick.regionParams.vector2Param1:Reset() _tempGetTargetsByJoystick.regionParams.shapeNumParams[1] = skillJoyStickData.ShapeParam1 _tempGetTargetsByJoystick.regionParams.shapeNumParams[2] = nil _tempGetTargetsByJoystick.sortParams.sortType = nil _tempGetTargetsByJoystick.sortParams.numParam1 = nil _tempGetTargetsByJoystick.sortParams.vector2Param1:Reset() result = TargetManager.GetTargets(entity, _tempGetTargetsByJoystick, count) end elseif skillJoyStickData.ShapeType == LuaConst.ESkillJoystickShapeType.FANSHAPE then _tempJoystickDir:Reset(joystickPos) _tempJoystickDir:Sub(entity:GetLogicPos()) _tempJoystickDir:Normalize() if count == 1 then result = TargetManager.GetNearestEnemyInFanShape( entity, skillJoyStickData.ShapeParam1, skillJoyStickData.ShapeParam2 * 2, false, false, skillJoyStickData.UEType ~= LuaConst.ESkillJoystickUEType.JOYSTICK_DIR and joystickPos or entity:GetLogicPos(), _tempJoystickDir, joystickPos, ignoreBeSkillTargetBuff, skillJoyStickData.DistType) else _tempGetTargetsByJoystick.ignoreBeSkillTargetBuff = ignoreBeSkillTargetBuff _tempGetTargetsByJoystick.regionParams.shapeType = LuaConst.ERegionShapeType.FANSHAPE _tempGetTargetsByJoystick.regionParams.pos:Reset(skillJoyStickData.UEType ~= LuaConst.ESkillJoystickUEType.JOYSTICK_DIR and joystickPos or entity:GetLogicPos()) _tempGetTargetsByJoystick.regionParams.vector2Param1:Reset(_tempJoystickDir) _tempGetTargetsByJoystick.regionParams.shapeNumParams[1] = skillJoyStickData.ShapeParam2 * 2 _tempGetTargetsByJoystick.regionParams.shapeNumParams[2] = skillJoyStickData.ShapeParam1 _tempGetTargetsByJoystick.sortParams.sortType = sortType or ETargetSortType.DIST_NEAR _tempGetTargetsByJoystick.sortParams.numParam1 = EDistType.DEFAULT_POINT_TO_POINT _tempGetTargetsByJoystick.sortParams.vector2Param1:Reset(_tempJoystickDir) --_tempGetTargetsByJoystick.sortParams.vector2Param2:Reset(joystickPos) result = TargetManager.GetTargets(entity, _tempGetTargetsByJoystick, count) end elseif skillJoyStickData.ShapeType == LuaConst.ESkillJoystickShapeType.RECT then _tempJoystickDir:Reset(joystickPos) _tempJoystickDir:Sub(entity:GetLogicPos()) _tempJoystickDir:Normalize() _tempGetTargetsByJoystick.ignoreBeSkillTargetBuff = ignoreBeSkillTargetBuff _tempGetTargetsByJoystick.regionParams.shapeType = LuaConst.ERegionShapeType.RECT _tempJoystickAimPos:Reset(_tempJoystickDir):Mul(skillJoyStickData.ShapeParam2):Mul(0.5) _tempJoystickAimPos:Add(skillJoyStickData.UEType ~= LuaConst.ESkillJoystickUEType.JOYSTICK_DIR and joystickPos or entity:GetLogicPos()) _tempGetTargetsByJoystick.regionParams.pos:Reset(_tempJoystickAimPos) _tempGetTargetsByJoystick.regionParams.vector2Param1:Reset(_tempJoystickDir) _tempGetTargetsByJoystick.regionParams.shapeNumParams[1] = skillJoyStickData.ShapeParam1 _tempGetTargetsByJoystick.regionParams.shapeNumParams[2] = skillJoyStickData.ShapeParam2 _tempGetTargetsByJoystick.sortParams.sortType = sortType or ETargetSortType.DIST_NEAR _tempGetTargetsByJoystick.sortParams.numParam1 = EDistType.DEFAULT_POINT_TO_POINT _tempGetTargetsByJoystick.sortParams.vector2Param1:Reset(_tempJoystickDir) if count == 1 then result = TargetManager.GetTarget(entity, _tempGetTargetsByJoystick) else result = TargetManager.GetTargets(entity, _tempGetTargetsByJoystick, count) end else logging.error(LTAG.ERROR, "HYW : 暂不支持指定形状的 双摇杆目标选择 ShapeType : ", skillJoyStickData.ShapeType, " 如果有需求需要跟战斗程序提 skillID : ", skillJoyStickData.ID) end return result end --返回所有敌人的数量 function TargetManager.GetEnemyCount(entity) return CampManager.GetEnitityCountExceptCampId(entity:GetCampID(), LuaConst.ECampID.NEUTRAL_PEACE) end function TargetManager.HasEnemyInCircle(entity,pos,radius,ignoreCanNotBeTargetBuff) local enemyList2d = TargetManager.Get2DEnemyList(entity) if enemyList2d then local radiusSqr = _tempV1:Reset(radius):Mul(radius) for i,list in ipairs(enemyList2d) do for j, entityTemp in ipairs(list) do if TargetManager.MatchState(entityTemp,ignoreCanNotBeTargetBuff) then if TargetManager.MatchDis(pos, entityTemp,radiusSqr) then return true end end end end end return false end function TargetManager.HasEnemyInRect(entity, pos, length, width, dir, ignoreCanNotBeTargetBuff, noInvincible) local enemyList2d = TargetManager.Get2DEnemyList(entity) if enemyList2d then for i,list in ipairs(enemyList2d) do for j, entityTemp in ipairs(list) do if TargetManager.MatchState(entityTemp, ignoreCanNotBeTargetBuff, noInvincible) then if FP.V2.IsInRectRange(entityTemp:GetLogicPos(), pos, dir, length, width) then return true end end end end end return false end -- center :当dir为false时表示一个点,否则表示一个方向 -- ignoreCanNotBeTargetBuff : 会选择身上挂有100047(不可被AI选为Target)Buff的目标 -- noInvincible : 不选择无敌的敌人 -- ignoreBeSkillTargetBuff : 为true时会选择身上没有100046(技能自动索敌能被锁到)Buff的目标 -- dir : 是一个vector2或nil.代表方向.传入的dir是一个经过原点的方向向量, 是某点pos减去center得到的方向. 如果只需要以点到点的距离来判定时,这个参数传nil即可. -- distType : 距离类型.为nil,0,1时使用点到点的距离, 为2时使用点到直线的距离, 为3时使用直线到直线的夹角. 为2,3时dir必须要传一个非零的vector2 -- viewer : 观看者,用来做视野判定。不传则不做视野判定 function TargetManager.GetNearestTargetIn2DList(center, list2d, ignoreCanNotBeTargetBuff, noInvincible, ignoreBeSkillTargetBuff, dir, distType, viewer) if ignoreBeSkillTargetBuff == nil then logging.error(LTAG.ERROR, "HYW : ignoreBeSkillTargetBuff 为空警告!") ignoreBeSkillTargetBuff = true end local target = nil _tempMinDis:Reset(0) _tempTargetDis:Reset(0) if dir and distType == LuaConst.EDistType.POINT_TO_LINE then _tempV1:Reset(dir.x):Mul(dir.x) _tempV1_2:Reset(dir.z):Mul(dir.z) _tempV1_3:Reset(_tempV1):Add(_tempV1_2) end for i,list in ipairs(list2d) do for j,other in ipairs(list) do if LevelManager.CurLevelFunc:CanSeeEntity(viewer, other) then if TargetManager.MatchStateAll(other,ignoreBeSkillTargetBuff,ignoreCanNotBeTargetBuff,noInvincible) then if distType == LuaConst.EDistType.POINT_TO_LINE then _tempVec2:Reset(other.components.move.LogicPos):Sub(center) --得到相对位置 _tempV1:Reset(dir.z):Mul(dir.z):Mul(_tempVec2.x):Mul(_tempVec2.x) --_tempV1最终值为点到直线距离的平方 _tempV1_2:Reset(-2):Mul(dir.x):Mul(dir.z):Mul(_tempVec2.x):Mul(_tempVec2.z) _tempV1:Add(_tempV1_2) _tempV1_2:Reset(dir.x):Mul(dir.x):Mul(_tempVec2.z):Mul(_tempVec2.z) _tempV1:Add(_tempV1_2):Div(_tempV1_3) _tempTargetDis:Reset(_tempV1) elseif distType == LuaConst.EDistType.LINE_ANGLE then _tempVec2:Reset(other.components.move.LogicPos):Sub(center) --得到相对位置 _tempTargetDis:Reset(0) FP.V2.Angle(dir, _tempVec2, _tempTargetDis) --这里只能用Angle,不能用Angle360 else FP.V2.DistanceSqr(center, other.components.move.LogicPos, _tempTargetDis) end if _tempMinDis > _tempTargetDis or not target then _tempMinDis:Reset(_tempTargetDis) target = other end end end end end return target end function TargetManager.GetMonsterListByMonsterType(monsterType, container) container = container or {} for i,entity in ipairs(LogicUpdateManager.EntityList_Normal) do if entity:IsMonster() and entity:GetFeatureID() == monsterType then table.insert(container, entity) end end return container end function TargetManager.GetMonsterListByMonsterID(monsterID, container) container = container or {} for i,entity in ipairs(LogicUpdateManager.EntityList_Normal) do if entity:IsMonster() and entity:GetCharacterID() == monsterID then table.insert(container, entity) end end return container end function TargetManager.MatchCharacter(entity, characterID, characterType) return (entity:GetCharacterType() == characterType or characterType == nil) and (entity:GetCharacterID() == characterID or characterID == nil) end --返回list2d中距离center最近的,且匹配characterID, characterType的单位。characterID或characterType如果为nil则代表该项不必匹配 function TargetManager.GetNearestCharacterIn2DList(center, list2d, characterID, characterType) local target = nil local min = nil for i,list in ipairs(list2d) do for j,other in ipairs(list) do if TargetManager.MatchCharacter(other, characterID, characterType) then local dis = FP.V2.DistanceSqr(center, other.components.move.LogicPos) --print("id", other._logicInitData.EntityID, "dis", dis) if not min or min > dis then min = dis target = other --print("change") end end end end return target end --返回list2d中距离center最近的,且在指定矩形内的,且匹配characterID, characterType的单位。characterID或characterType如果为nil则代表该项不必匹配 function TargetManager.GetNearestCharacterIn2DListWithinRect(entity, list2d, center, length, width, dir, characterID, characterType) local result local minDistSqr = FP.newV1(9999999) local distSqr for i,entityList in ipairs(list2d) do for j, entityTemp in ipairs(entityList) do if TargetManager.MatchCharacter(entityTemp, characterID, characterType) then if FP.V2.IsInRectRange(entityTemp:GetLogicPos(),center,dir,length,width) then distSqr = entityTemp:GetLogicPos():DistanceSqr(entity:GetLogicPos()) if minDistSqr > distSqr then minDistSqr:Reset(distSqr) result = entityTemp end end end end end return result end function TargetManager.Match(entity, tempEntity, camp, monsterType, disSqr,ignoreCanNotBeTargetBuff,noInvincible) return TargetManager.MatchCamp(entity, tempEntity, camp) and TargetManager.MatchState(tempEntity,ignoreCanNotBeTargetBuff,noInvincible) and TargetManager.MatchSearchUnitType(entity,tempEntity, monsterType) and TargetManager.MatchDis(entity.components.move.LogicPos, tempEntity, disSqr) and LevelManager.CurLevelFunc:CanSeeEntity(entity, tempEntity) end function TargetManager.MatchSearchUnitType(entity,tempEntity, unitType) local characterType = tempEntity._logicInitData.CharacterType local result = true if unitType == _EUnitType.ANY then result = true elseif unitType == _EUnitType.HERO then --玩家 if characterType ~= LuaConst.CharacterType.Hero then result = false end elseif unitType == _EUnitType.NPC then --NPC if characterType ~= LuaConst.CharacterType.NPC then result = false end elseif unitType == _EUnitType.SUMMON_MASTER then result = tempEntity:IsMasterEntity(entity) elseif TargetManager.IsMonsterType(unitType) then if characterType == LuaConst.CharacterType.Monster then result = (unitType == tempEntity._logicInitData._characterData.MonsterType + LuaConst.MONSTER_TYPE_2_SERACH_TYPE_PLUS) --规定死了,映射是+100(MONSTER_TYPE_2_SERACH_TYPE_PLUS) --这块代码不太对了,可以删掉了。目前应该只用保留判断是Monster即可 else result = false end end return result end function TargetManager.SwtichForcePlayer(playerID,forcePlayerID) --此处对playerID的所有entity设置强制目标 local entityTable = LevelPlayerManager.GetPlayerEntitysByPlayerIDInRoom(playerID) local isSet for i,entity in ipairs(entityTable) do isSet = entity.components.target:SwtichForcePlayer(forcePlayerID) end return isSet end --设置强制目标玩家(对应世界boss模式的强制模式 function TargetManager.SwtichForceTeam(playerID, forceTeamID) --此处对playerID的所有entity设置强制目标 local entityTable = LevelPlayerManager.GetPlayerEntitysByPlayerIDInRoom(playerID) local isSet for i,entity in ipairs(entityTable) do isSet = entity.components.target:SwtichForceTeam(forceTeamID) end return isSet end --设置强制目标(对应世界boss模式的强制模式 function TargetManager.SetForceTarget(entity,target) entity.components.target:SetForceTarget(target) end function TargetManager.MatchCamp(entity, tempEntity, camp) --camp == 2,友方不包括自己 --传入的entity为友方,需要排除下自己 if camp == 2 and entity._logicInitData.EntityID == tempEntity._logicInitData.EntityID then return false end if camp == 1 then --敌方 if entity.components.target:IsIgnoreEnemey(tempEntity) then return false end end return true end function TargetManager.MatchDis(pos, tempEntity, disSqr) return not FP.V2.IsDistanceSqrGreater(pos, tempEntity.components.move.LogicPos, disSqr) end -- noInvincible : 不选择无敌的敌人 -- ignoreBeSkillTargetBuff : 为true时会选择身上没有100046(技能自动索敌能被锁到)Buff的目标 function TargetManager.MatchStateSkill(tempEntity,ignoreBeSkillTargetBuff,noInvincible) local buffComp = tempEntity.components.buff if not ignoreBeSkillTargetBuff and not buffComp:GetBuffUpdateData(LuaConst.SpecialBuffs.BeSkillTarget) then return false end if buffComp:GetBuffUpdateData(LuaConst.SpecialBuffs.CantBeTrigger) then return false end if noInvincible and buffComp.HasBuffOfInvicibleGroup 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 end --noInvincible : 不选择无敌的单位 function TargetManager.MatchState(tempEntity,ignoreCanNotBeTargetBuff,noInvincible) local buffComp = tempEntity.components.buff if not ignoreCanNotBeTargetBuff and buffComp:GetBuffUpdateData(LuaConst.SpecialBuffs.CanNotBeTarget) then return false end if buffComp:GetBuffUpdateData(LuaConst.SpecialBuffs.CantBeTrigger) then return false end if noInvincible and buffComp.HasBuffOfInvicibleGroup 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 end -- ignoreCanNotBeTargetBuff : 会选择身上挂有100047(不可被AI选为Target)Buff的目标 -- noInvincible : 不选择无敌的敌人 -- ignoreBeSkillTargetBuff : 为true时会选择身上没有100046(技能自动索敌能被锁到)Buff的目标 function TargetManager.MatchStateAll(tempEntity,ignoreBeSkillTargetBuff,ignoreCanNotBeTargetBuff,noInvincible) local buffComp = tempEntity.components.buff if not ignoreBeSkillTargetBuff and not buffComp:GetBuffUpdateData(LuaConst.SpecialBuffs.BeSkillTarget) then return false end if not ignoreCanNotBeTargetBuff and buffComp:GetBuffUpdateData(LuaConst.SpecialBuffs.CanNotBeTarget) then return false end if buffComp:GetBuffUpdateData(LuaConst.SpecialBuffs.CantBeTrigger) then return false end if noInvincible and buffComp.HasBuffOfInvicibleGroup 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 end function TargetManager.IsMonsterType(unitType) return unitType and unitType >= _EUnitType.MONSTER_START and unitType <= _EUnitType.MONSTER_END end --让entity索敌时忽略所有的Hero和Hero的召唤物 function TargetManager.IgnoreAllHeroEnemey(entity) local targetComponent = entity.components.target targetComponent:ClearIgnoreEnemy() local enemyList2d = TargetManager.Get2DEnemyList(entity) for i,enemyList in ipairs(enemyList2d) do if enemyList then for j,enemy in ipairs(enemyList) do if enemy:GetCharacterType() == LuaConst.CharacterType.Hero then targetComponent:AddIgnoreEnemyEntity(enemy) else local masterEntity = enemy:GetMasterEntity() if masterEntity and masterEntity:IsHero() then targetComponent:AddIgnoreEnemyEntity(enemy) end end end end end end function TargetManager.IgnoreEnemyOfMonsterType(entity,monsterTypes) entity.components.target:AddIgnoreEnemyMonsterTypes(monsterTypes) end function TargetManager.IgnoreEnemyOfCharacterType(entity,charTypes) entity.components.target:AddIgnoreEnemyCharacterTypes(charTypes) end local __distanceCenter = FP.newV2(0, 0) local function DistanceNearSorter(entityA, entityB) _tempVec2:Reset(entityA:GetLogicPos()):Sub(__distanceCenter):SqrMagnitude(_tempV1) _tempVec2:Reset(entityB:GetLogicPos()):Sub(__distanceCenter):SqrMagnitude(_tempV1_2) return _tempV1 < _tempV1_2 end local function DistanceFarSorter(entityA, entityB) _tempVec2:Reset(entityA:GetLogicPos()):Sub(__distanceCenter):SqrMagnitude(_tempV1) _tempVec2:Reset(entityB:GetLogicPos()):Sub(__distanceCenter):SqrMagnitude(_tempV1_2) return _tempV1 > _tempV1_2 end local __distanceDir = FP.newV2(0, 0) local function DistanceToLineNearSorter(entityA, entityB) _tempVec2:Reset(entityA:GetLogicPos()):Sub(__distanceCenter) FP.V2.DistanceSqrToDir(_tempVec2, __distanceDir, _tempV1) _tempVec2:Reset(entityB:GetLogicPos()):Sub(__distanceCenter) FP.V2.DistanceSqrToDir(_tempVec2, __distanceDir, _tempV1_2) return _tempV1 < _tempV1_2 end local function DistanceToLineFarSorter(entityA, entityB) _tempVec2:Reset(entityA:GetLogicPos()):Sub(__distanceCenter) FP.V2.DistanceSqrToDir(_tempVec2, __distanceDir, _tempV1) _tempVec2:Reset(entityB:GetLogicPos()):Sub(__distanceCenter) FP.V2.DistanceSqrToDir(_tempVec2, __distanceDir, _tempV1_2) return _tempV1 > _tempV1_2 end local function AngleToLineNearSorter(entityA, entityB) _tempVec2:Reset(entityA:GetLogicPos()):Sub(__distanceCenter) FP.V2.Angle(_tempVec2, __distanceDir, _tempV1)--这里只能用Angle,不能用Angle360 _tempVec2:Reset(entityB:GetLogicPos()):Sub(__distanceCenter) FP.V2.Angle(_tempVec2, __distanceDir, _tempV1_2)--这里只能用Angle,不能用Angle360 return _tempV1 < _tempV1_2 end local function AngleToLineFarSorter(entityA, entityB) _tempVec2:Reset(entityA:GetLogicPos()):Sub(__distanceCenter) FP.V2.Angle(_tempVec2, __distanceDir, _tempV1)--这里只能用Angle,不能用Angle360 _tempVec2:Reset(entityB:GetLogicPos()):Sub(__distanceCenter) FP.V2.Angle(_tempVec2, __distanceDir, _tempV1_2)--这里只能用Angle,不能用Angle360 return _tempV1 < _tempV1_2 end local REALTIME_ATTR_HP = LuaConst.RealtimeAttrType.hp local function HpLowSorter(entityA, entityB) return entityA.components.attr:GetAttrValue(REALTIME_ATTR_HP) < entityB.components.attr:GetAttrValue(REALTIME_ATTR_HP) end local function HpPecentLowSorter(entityA, entityB) return entityA.components.attr:HitPointPercents(_tempV1) < entityB.components.attr:HitPointPercents(_tempV1_2) end local function HpHighSorter(entityA, entityB) return entityA.components.attr:GetAttrValue(REALTIME_ATTR_HP) > entityB.components.attr:GetAttrValue(REALTIME_ATTR_HP) end local function HpPercentHighSorter(entityA, entityB) return entityA.components.attr:HitPointPercents(_tempV1) > entityB.components.attr:HitPointPercents(_tempV1_2) end local function Shuffle(list) local rand local temp for i=#list,1,-1 do rand = LogicRandom.GetIntegerValue(nil, 1, i) temp = list[i] list[i] = list[rand] list[rand] = temp end end --默认的单位优先级Getter,Boss > 精英 > 其他 local function DefaultEntityPriorityGetter(entity) --返回单位的目标优先级,越大则在查找时越优先被查找 local priority = 1 if entity:IsBoss() then priority = 3 elseif entity:IsElite() then priority = 2 end return priority end local __priorityGetter --Priority越大越靠前 local function PrioritySorter(entityA, entityB) return __priorityGetter(entityA) > __priorityGetter(entityB) end function TargetManager.SortTargetList(entity, list, sortParams) -- 参数说明: -- sortParams = { -- sortType = ETargetSortType.DIST_NEAR, -- numParam1, -- --sortType == ETargetSortType.DIST_NEAR或 sortType == DIST_FAR时,指定距离类型,为EDistType的枚举值 传nil、0、1=点到点距离;2=点到直线的距离;3=角度距离(夹角大小) -- numParam2, -- --没用到 -- vector2Param1, -- --sortType == ETargetSortType.DIST_NEAR或 sortType == DIST_FAR时,指定距离判定的中心点,如果设为nil,则以entity的位置为中心点 -- vector2Param2, -- --sortType == ETargetSortType.DIST_NEAR或 sortType == DIST_FAR 且 numParam1 == 2或3(EDistType.POINT_TO_LINE 、 EDistType.LINE_ANGLE)时,指定一条直线或角度的一条边 -- priorityGetter, -- --优先级Getter function,当 sortType == PRIORITY时,可以传入自定义的优先级Getter,Getter参数为Entity,返回一个number类型的优先级。优先级越高的Entity会被排在越前面 -- --priorityGetter为nil时,会使用 DefaultEntityPriorityGetter, 以Boss > 精英 > 其他单位 的顺序返回Priority -- }, local sortType = sortParams.sortType if sortType == ETargetSortType.DIST_NEAR or sortType == ETargetSortType.DIST_FAR then local distType = sortParams.numParam1 local pos = sortParams.vector2Param1 or entity:GetLogicPos() __distanceCenter:Reset(pos) if distType == EDistType.DEFAULT_POINT_TO_POINT or distType == EDistType.POINT_TO_POINT or distType == nil then --点到点的距离排序 if sortType == ETargetSortType.DIST_NEAR then table.sort(list, DistanceNearSorter) else table.sort(list, DistanceFarSorter) end elseif distType == EDistType.POINT_TO_LINE then __distanceDir:Reset(sortParams.vector2Param2 or entity.components.move:GetLogicRotateDir()) if sortType == ETargetSortType.DIST_NEAR then table.sort(list, DistanceToLineNearSorter) else table.sort(list, DistanceToLineFarSorter) end elseif distType == EDistType.LINE_ANGLE then __distanceDir:Reset(sortParams.vector2Param2 or entity.components.move:GetLogicRotateDir()) if sortType == ETargetSortType.DIST_NEAR then table.sort(list, AngleToLineNearSorter) else table.sort(list, AngleToLineFarSorter) end end elseif sortType == ETargetSortType.HP_PERCENT_LOW then table.sort(list, HpPecentLowSorter) elseif sortType == ETargetSortType.HP_PERCENT_HIGH then table.sort(list, HpPercentHighSorter) elseif sortType == ETargetSortType.HP_LOW then table.sort(list, HpLowSorter) elseif sortType == ETargetSortType.HP_HIGH then table.sort(list, HpHighSorter) elseif sortType == ETargetSortType.RANDOM then Shuffle(list) elseif sortType == ETargetSortType.PRIORITY then __priorityGetter = sortParams.priorityGetter or DefaultEntityPriorityGetter table.sort(list, PrioritySorter) end -- if list then -- for i,_entity in ipairs(list) do -- logging.error(LTAG.ERROR, "HYW : ", _entity.EntityID) -- end -- end end --目标查找过滤流程,包含多个环节,可以拓展环节以支持新需求 --list是备选目标列表 function TargetManager.FilterTargetList(entity, list, params) local regionParams = params.regionParams local shapeType local radiusSqr if regionParams then shapeType = regionParams.shapeType if shapeType == ERegionShapeType.CIRCLE then radiusSqr = FP.newV1(0) radiusSqr:Reset(regionParams.shapeNumParams[1]):Mul(regionParams.shapeNumParams[1]) --这么写鲁棒性好点,可以cover 定点数和number两种情况(之前是radiusSqr = FP.newV1(regionParams.shapeNumParams[1]), 限定死了regionParams.shapeNumParams[1]只能为number) end end local conditionTree if params.conditionStr then conditionTree = ConditionManager.GetConditionDataTree(params.conditionStr) end local visualFieldComp = entity.components.visualField local buffComp local _entity for i=#list,1,-1 do _entity = list[i] buffComp = _entity.components.buff repeat --之前一直没有过滤死人和没有激活的人,现在才加上(2022年7月22日) if not _entity:IsActive() or not _entity:IsAlive() then table.remove(list, i) break end --尝试过滤掉不在视野内的对象 if not LevelManager.CurLevelFunc:CanSeeEntity(entity, _entity) then table.remove(list, i) break end --尝试过滤掉身上挂有 CanNotBeTarget(100047,不可作为目标)的单位 if not params.ignoreCanNotBeTargetBuff then if buffComp:GetBuffUpdateData(LuaConst.SpecialBuffs.CanNotBeTarget) then table.remove(list, i) break end end --尝试过滤掉身上没有 BeSkillTarget(100046,可作为技能目标)的单位 if not params.ignoreBeSkillTargetBuff then if not buffComp:GetBuffUpdateData(LuaConst.SpecialBuffs.BeSkillTarget) then table.remove(list, i) break end end --尝试过滤掉无敌的单位 if params.noInvincible then if buffComp.HasBuffOfInvicibleGroup then table.remove(list, i) break end end --尝试过滤掉主体的忽略敌人列表里的敌人(targetComponent提供的机制) if params.ignoreEnemyListValid and params.campType == ETargetCampType.ENEMY then if entity.components.target:IsIgnoreEnemey(_entity) then table.remove(list, i) break end end --尝试过滤掉不符合 monsterTypes 指定若干种类型的单位 if params.monsterTypes then local isMonsterTypeMatch = false for monsterTypeIndex,monsterType in ipairs(params.monsterTypes) do if TargetManager.MatchSearchUnitType(entity, _entity, monsterType) then isMonsterTypeMatch = true break end end if not isMonsterTypeMatch then table.remove(list, i) break end end --尝试过滤掉排除列表里的对象 if params.exclusions then local shouldRemove for j,exlcudedEntity in ipairs(params.exclusions) do if exlcudedEntity == _entity then shouldRemove = true break end end if shouldRemove then table.remove(list, i) break end end --尝试过滤掉不满足条件的对象(使用通用的ConditionManager模块, ConditionManager.MeetCondition方法) if params.conditionStr then if conditionTree then if not ConditionManager.MeetCondition(_entity, conditionTree) then table.remove(list, i) break end else logging.error(LTAG.ERROR, "HYW : 创建条件树失败 @TargetManager.GetTarget") end end --尝试过滤掉不在指定区域的对象 if regionParams then if shapeType == ERegionShapeType.CIRCLE then --圆形区域 if not TargetManager.MatchDis(regionParams.pos or entity:GetLogicPos(), _entity, radiusSqr) then table.remove(list, i) break end elseif shapeType == ERegionShapeType.RECT then local dir = regionParams.vector2Param1 or entity.components.move:GetLogicRotateDir() local length local width if not FP.V2.IsInRectRange(_entity:GetLogicPos(), regionParams.pos or entity:GetLogicPos(), dir, regionParams.shapeNumParams[1], regionParams.shapeNumParams[2]) then table.remove(list, i) break end elseif shapeType == ERegionShapeType.FANSHAPE then local dir = regionParams.vector2Param1 or entity.components.move:GetLogicRotateDir() if not FP.V2.IsInFanshape(_entity:GetLogicPos(), regionParams.pos or entity:GetLogicPos(), dir, regionParams.shapeNumParams[1], regionParams.shapeNumParams[2]) then table.remove(list, i) break end end end until true end end function TargetManager.GetEntityListCopyByCampType(entity, campType) local list if campType == ETargetCampType.ENEMY then list = TargetManager.GetEnemyListCopy(entity) elseif campType == ETargetCampType.FRIEND_EXCLUDE_SELF then list = TargetManager.GetFriendListCopyExcludeSelf(entity) elseif campType == ETargetCampType.ONLY_SELF then list = {entity} elseif campType == ETargetCampType.FRIEND_INCLUDE_SELF then list = TargetManager.GetFriendListCopy(entity) elseif campType == ETargetCampType.ALL then list = TargetManager.GetEntityListCopyOfAll(entity) else logging.error(LTAG.ERROR, "HYW : 没有指定备选目标阵营类型, 获取目标失败") end return list end --返回过滤了的、排序过的目标列表 --目标查找流程:先过滤,再排序 function TargetManager.GetFilteredSortedTargetList(entity, params) local list repeat --获取初始备选list,根据campType list = TargetManager.GetEntityListCopyByCampType(entity, params.campType) --备选目标的数组 if not list then break end --过滤流程 TargetManager.FilterTargetList(entity, list, params) --排序流程 if params.sortParams then TargetManager.SortTargetList(entity, list, params.sortParams) end until true return list end -------------统一目标查找新接口↓------------------------------------------------------ --获取目标接口参数说明 -- local params = { -- -----------------过滤参数↓ -- campType, -- ETargetCampType -- --campParam, -- 阵营参数(目前看不需要) -- ignoreCanNotBeTargetBuff, -- ignoreCanNotBeTargetBuff : 会选择身上挂有100047(不可被AI选为Target)Buff的目标 --填true表示不过滤,默认为nil时也会过滤 -- ignoreBeSkillTargetBuff, --填true表示不过滤,默认为nil时也会过滤 -- noInvincible, -- noInvincible : 不选择无敌的敌人 --填true表示不选择无敌的目标,不填或者填false表示可能选择无敌的目标 -- ignoreEnemyListValid, --填true时在寻找敌人目标时,如果备选目标传入TargetComponent:IsIgnoreEnemey方法返回的是true,则忽略该备选目标 -- monsterTypes, --限定怪物类型数组,元素是_EUnitType的枚举值 -- exclusions, --排除列表,里面的元素是Entity对象,处于这个列表内的单位会被排除 -- conditionStr, --条件字串,过滤掉不符合条件的单位 -- regionParams = --区域参数组,过滤掉不在区域内的单位 -- { -- shapeType = ERegionShapeType.CIRCLE, -- pos, --位置(圆心/矩形中心/扇形圆心),是一个vector2. 如果为nil,会使用目标查询主体entity的位置。 -- vector2Param1, --vector2参数1 -- --vector2Param1说明: -- --当shapeType == ERegionShapeType.CIRCLE时,无作用 -- --当shapeType == ERegionShapeType.RECT时,vector2Param1是矩形方向(跟length所指定的边平行),如果为nil则使用entity的面向 -- --当shapeType == ERegionShapeType.FANSHAPE,vector2Param1是扇形的中心线的方向,如果为nil则使用entity的面向 -- shapeNumParams, --number参数数组 -- --shapeNumParams说明: -- --当shapeType == ERegionShapeType.CIRCLE时,shapeNumParams[1]是圆形的半径 -- --当shapeType == ERegionShapeType.RECT时, shapeNumParams[1]是矩形的width(垂直矩形方向vector2Param1的),shapeNumParams[2]是矩形的length(顺着矩形方向vector2Param1的) -- --当shapeType == ERegionShapeType.FANSHAPE, shapeNumParams[1]是扇形的角度(角度制),shapeNumParams[2]是扇形的半径 -- }, -- ------------------过滤参数↑ -- ------------------排序参数↓ -- sortParams = { -- sortType = ETargetSortType.DIST_NEAR, -- numParam1, -- --numParam1说明: -- --sortType == ETargetSortType.DIST_NEAR或 sortType == DIST_FAR时,指定距离类型,为EDistType的枚举值 传nil、0、1=点到点距离;2=点到直线的距离;3=角度距离(夹角大小) -- numParam2, -- vector2Param1, -- --vector2Param1说明: -- --sortType == ETargetSortType.DIST_NEAR或 sortType == DIST_FAR时,指定距离判定的中心点,如果设为nil,则以entity的位置为中心点 -- vector2Param2, -- --vector2Param2说明: -- --sortType == ETargetSortType.DIST_NEAR或 sortType == DIST_FAR 且 numParam1 == 2或3(EDistType.POINT_TO_LINE 、 EDistType.LINE_ANGLE)时,指定一条直线或角度的一条边 -- priorityGetter, --优先级Getter function,当 sortType == PRIORITY时,可以传入自定义的优先级Getter,Getter参数为Entity,返回一个number类型的优先级。优先级越高的Entity会被排在越前面 -- --priorityGetter为nil时,会使用 DefaultEntityPriorityGetter, 以Boss > 精英 > 其他单位 的顺序返回Priority -- }, -- -----------------排序参数↑ -- } --获取单个目标 function TargetManager.GetTarget(entity, params) local list = TargetManager.GetFilteredSortedTargetList(entity, params) return list and list[1] end --获取多个目标,可能返回nil或一个table数组 --maxCount:最大选取数量 --minCount:最小获取数量,如果最终可选目标数量小于minCount, 则返回nil。 如果minCoun传nil,则不限制最小数量 function TargetManager.GetTargets(entity, params, maxCount, minCount) local result = nil repeat result = TargetManager.GetFilteredSortedTargetList(entity, params) if not result then break end if minCount and #result < minCount then --可选目标数量小于minCount,则什么都不返回 result = nil break end for i=maxCount+1,#result do result[i] = nil end until true -- if result then -- logging.error(LTAG.ERROR, "HYW : GetTargets result -----------") -- for i,entity in ipairs(result) do -- logging.error(LTAG.ERROR, "HYW : ", entity.EntityID) -- end -- end return result end -----------统一目标查找新接口↑------------------------------------------------------- return TargetManager