using System; using Framework; using UnityEngine; using System.Linq; using Gameplay.Unit; using Gameplay.Area; using Gameplay.Level; using cfg.CharacterCfg; using Gameplay.Unit.Data; using Gameplay.Character; using Gameplay.Area.Around; using Gameplay.Vehicle.Impl; using System.Collections.Generic; using static Gameplay.Level.LevelData; namespace Gameplay.AI { public static partial class AIUtils { private static List inSightEnemies = new List(16); private static Dictionary inSightDistanceList = new Dictionary(16); private static List allFriends = new List(16); private static List friendsInSight = new List(16); private static Dictionary patrolDistanceList = new Dictionary(64); /// /// 寻找锁敌范围内最近的敌人 /// public static GameUnit FindNearestEnemyInSightDistance(GameUnit owner) { try { if (owner == null) return null; var map = LevelManager.Instance.CurrentLevel.Map; if (map == null) return null; inSightDistanceList.Clear(); var enemies = GameUnitManager.instance.SearchEnemies(owner); var ownerCellIndex = owner.transData?.cellIndex; for (var i = 0; i < enemies.Count; i++) { var enemy = enemies[i]; if (enemy == null || enemy.statusData.isDead) { continue; } var enemyCellIndex = enemy.transData?.cellIndex; if (!ownerCellIndex.HasValue || !enemyCellIndex.HasValue) { continue; } var distance = MapUtils.Distance(map, ownerCellIndex.Value, enemyCellIndex.Value); if (distance <= owner.fightData.findEnemyRange && enemy.statusData.CheckCanBeTarget(owner, (int)owner.fightData.findEnemyRange)) { inSightDistanceList.Add(enemy, distance); } } if (inSightDistanceList.Count <= 0) { return null; } else { var minDistance = float.MaxValue; GameUnit nearestEnemy = null; foreach (var pair in inSightDistanceList) { if (minDistance > pair.Value) { minDistance = pair.Value; nearestEnemy = pair.Key; } } return nearestEnemy; } } catch (Exception e) { DebugUtil.LogError("AIUtils.FindNearestEnemyInSightDistance error: {0}", e); return null; } } /// /// 寻找锁敌范围内的友军 /// public static List FindFriendsInSightDistance(GameUnit owner) { try { if (owner == null) return null; var map = LevelManager.Instance.CurrentLevel.Map; if (map == null) return null; friendsInSight.Clear(); var friends = GameUnitManager.instance.SearchFriends(owner); var ownerCellIndex = owner.transData?.cellIndex; for (var i = 0; i < friends.Count; i++) { var friend = friends[i]; if (friend == null || friend.GetID() == owner.GetID()) { continue; } var friendCellIndex = friend.transData?.cellIndex; if (!ownerCellIndex.HasValue || !friendCellIndex.HasValue) { continue; } var distance = MapUtils.Distance(map, ownerCellIndex.Value, friendCellIndex.Value); if (distance <= owner.fightData.findEnemyRange) { friendsInSight.Add(friend); } } return friendsInSight; } catch (Exception e) { DebugUtil.LogError("AIUtils.FindFriendsInSightDistance error: {0}", e); return null; } } /// /// 寻找范围内最近的敌方npc /// public static GameUnit FindNearestEnemyNpcInShootRange(GameUnit owner) { try { var enemyNpc = FindEnemyNpcInSight(owner); if (enemyNpc == null || enemyNpc.Count <= 0) return null; GameUnit nearestEnemy = null; var minDistance = float.MaxValue; foreach (var pair in enemyNpc) { if (minDistance > pair.Value) { minDistance = pair.Value; nearestEnemy = pair.Key; } } return nearestEnemy; } catch (Exception e) { DebugUtil.LogError("AIUtils.FindNearestEnemyNpcInShootRange error: {0}", e); return null; } } /// /// 获取距离自己最近的单位 /// public static GameUnit GetNearestGameUnit(GameUnit owner, GameUnit newUnit, GameUnit unit) { try { if (owner == null || newUnit == null || unit == null) return null; var map = LevelManager.Instance.CurrentLevel.Map; if (map == null) return null; var ownerCellIndex = owner.transData?.cellIndex; var unitCellIndex = unit.transData?.cellIndex; var newUnitCellIndex = newUnit.transData?.cellIndex; if (!ownerCellIndex.HasValue || !unitCellIndex.HasValue || !newUnitCellIndex.HasValue) return null; var distance = MapUtils.Distance(map, ownerCellIndex.Value, unitCellIndex.Value); var newDistance = MapUtils.Distance(map, ownerCellIndex.Value, newUnitCellIndex.Value); return distance <= newDistance ? unit : newUnit; } catch (Exception e) { DebugUtil.LogError("AIUtils.GetNearestGameUnit error: {0}", e); // 异常返回默认单位 return unit; } } /// /// 寻找最近的巡逻点位 /// public static int FindNearestPointInPatrolInfo(GameUnit owner, List patrolInfos) { try { if (owner == null) return Constants.INVALID_ID; var map = LevelManager.Instance.CurrentLevel.Map; if (map == null) return Constants.INVALID_ID; patrolDistanceList.Clear(); var ownerCellIndex = owner.transData?.cellIndex; for (var i = 0; i < patrolInfos.Count; i++) { var point = map.BlockPosition2TGSCellIndex(patrolInfos[i].patrolPoint); if (!ownerCellIndex.HasValue || point == Constants.INVALID_ID) { continue; } patrolDistanceList.Add(i, MapUtils.Distance(map, ownerCellIndex.Value, point)); } var minDistance = int.MaxValue; int nearestPoint = 0; foreach (var pair in patrolDistanceList) { if (minDistance > pair.Value) { minDistance = pair.Value; nearestPoint = pair.Key; } } return nearestPoint; } catch (Exception e) { DebugUtil.LogError("AIUtils.FindNearestPointInPatrolInfo error: {0}", e); // 异常返回第一个索引点 return 0; } } /// /// 巡逻点位转换为格子索引 /// public static int GetPatrolPointIndexFromVector2Int(Map map, int patrolIndex, List patrolInfos) { try { if (map == null || patrolIndex >= patrolInfos.Count) return -1; var patrolInfo = patrolInfos[patrolIndex]; if (patrolInfo == null) return -1; return map.BlockPosition2TGSCellIndex(patrolInfo.patrolPoint); } catch (Exception e) { DebugUtil.LogError("AIUtils.GetPatrolPointIndexFromVector2Int error: {0}", e); // 异常返回无效格子索引 return -1; } } /// /// 是否停止循环逻辑 /// public static bool AINeedStopUpdate(global::Gameplay.Level.Level level) { if (level == null) return false; return level.IsPreparing() || level.IsEnd() || Math.Abs(level.GetSpeed() - 0f) < 0.01f; } /// /// 激活AI攻击 /// public static void ActiveAIAttack(GameUnit owner) { try { if (owner == null) return; if (owner.statusData.isAttackActive) return; var map = LevelManager.Instance.CurrentLevel.Map; if (map == null) return; if (owner.controlData.targetEnemy != null) { owner.statusData.isAttackActive = true; owner.statusData.isInFight = true; } } catch (Exception e) { DebugUtil.LogError("AIUtils.ActiveAIAttack error: {0}", e); } } /// /// 单位移动 /// public static bool MoveTo(GameUnit owner, int cellIndex, bool cancelFollow = true) { try { if (owner == null || cellIndex == -1) return false; var map = LevelManager.Instance.CurrentLevel.Map; if (map == null) return false; var mapData = map.MapData; if (mapData == null) return false; var blockData = mapData.GetBlockData(cellIndex); if (blockData == null) return false; var typeProperty = blockData.GetTerrainTypeProperty(); if (typeProperty == null || !typeProperty.selectable) return false; owner.MoveTo(cellIndex, cancelFollow); return true; } catch (Exception e) { DebugUtil.LogError("AIUtils.MoveTo error: {0}", e); return false; } } /// /// 单位撤退 /// /// public static bool MoveAway(GameUnit owner, GameUnit enemyUnit, bool cancelFollow = true) { try { if (enemyUnit == null) return false; var map = LevelManager.Instance.CurrentLevel.Map; if (map == null) return false; var mapData = map.MapData; if (mapData == null) return false; map.WorldPosition2BlockPosition(enemyUnit.Node.GetPosition(), out var targetEnemy2IntPos); var self2IntPos = map.TGSCellIndex2BlockPosition(owner.transData.cellIndex); var newSelf2IntPos = self2IntPos; newSelf2IntPos.x = Math.Clamp( (self2IntPos.x - targetEnemy2IntPos.x) > 0 ? self2IntPos.x + 1 : self2IntPos.x - 1, 0, map.MapData.Height - 1); newSelf2IntPos.y = Math.Clamp( (self2IntPos.y - targetEnemy2IntPos.y) > 0 ? self2IntPos.y + 1 : self2IntPos.y - 1, 0, map.MapData.Width - 1); if (self2IntPos == newSelf2IntPos) return false; var cellIndex = map.BlockPosition2TGSCellIndex(newSelf2IntPos); if (PathFinder.CanPass(cellIndex, owner)) { owner.MoveTo(cellIndex, cancelFollow); return true; } return false; } catch (Exception e) { DebugUtil.LogError("AIUtils.MoveAway error: {0}", e); return false; } } /// /// AI 移动向敌人并检查 /// public static void CheckAndMove(GameUnit owner, int cellIndex, bool cancelFollow = true) { try { if (!MoveTo(owner, cellIndex, cancelFollow)) return; if (owner.gameunitType != EGameUnitType.Character && owner.gameunitType != EGameUnitType.Vehicle) return; var units = AreaManager.instance.GetUnitsByCellIndex(cellIndex); foreach (var unit in units) { if (unit.commonData.troopId == owner.commonData.troopId) { } else { // 如果是敌人, 则设置敌人目标 if (unit.statusData.CheckCanBeTarget(owner, -1)) { owner.controlData.markEnemy = unit; owner.controlData.forceUpdateTarget = true; return; } } } // 走到这里,说明没有目标,清空标记 owner.controlData.markVehicle = null; owner.controlData.markEnemy = null; } catch (Exception e) { DebugUtil.LogError("AIUtils.CheckAndMove error: {0}", e); } } /// /// 判断是否有敌人重合 /// public static void CheckAreaIsOtherEnemyUnit(GameUnit owner, uint target) { try { if (owner == null || owner.statusData.isMoveing) return; var cellIndex = owner.transData.cellIndex; var units = AreaManager.instance.GetUnitsByCellIndex(cellIndex); var hasOther = false; foreach (var unit in units) { if (unit == owner) continue; if (!unit.commonData.canClaimStandCellIndex) continue; if (unit.statusData.isMoveing) continue; hasOther = true; break; } if (!hasOther) return; if (target == Constants.INVALID_UINT_ID) { MoveOtherCell(owner); } else { var enemy = GameUnitManager.instance.infightUnits.Search(target); if (enemy == null || enemy.statusData.isDead) return; MoveOtherCanAttackCell(owner, enemy); } } catch (Exception e) { DebugUtil.LogError("AIUtils.CheckAreaIsOtherEnemyUnit error: {0}", e); } } /// /// 移动至周围可到达格子 /// private static void MoveOtherCell(GameUnit owner, int maxDistance = 2) { try { var map = LevelManager.Instance.CurrentLevel?.Map; if (map == null || owner == null) return; var cellIndex = owner.transData.cellIndex; if (!AreaManager.instance.CheckContainsMoveUnit(cellIndex)) return; for (var i = 1; i <= maxDistance; i++) { var minSteps = i - 1; var maxSteps = i; var cells = map.TerrainGridSystem.CellGetNeighboursWithinRange(cellIndex, minSteps, maxSteps, canCrossCheckType: TGS.CanCrossCheckType.IgnoreCanCrossCheckOnAllCells); foreach (var cell in cells) { if (!CheckCellCanSelect(cell)) continue; if (!PathFinder.CanBasePass(cell, owner)) continue; if (AreaManager.instance.CheckContainsMoveUnit(cell)) continue; if (maxSteps > 1) { if (CheckPathExits(owner, cell)) { owner.controlData.targetCellIndex = cell; return; } } else { owner.controlData.targetCellIndex = cell; return; } } } // 无处可去 owner.MoveTo(owner.transData.bornCellIndex, true); } catch (Exception e) { DebugUtil.LogError("AIUtils.MoveOtherCell error: {0}", e); } } /// /// 移动至周围可攻击格子 /// private static void MoveOtherCanAttackCell(GameUnit owner, GameUnit enemy, int maxDistance = 2) { try { var map = LevelManager.Instance.CurrentLevel?.Map; if (map == null || owner == null || enemy == null) return; var enemyCellIndex = enemy.transData.cellIndex; var cellIndex = owner.transData.cellIndex; if (!AreaManager.instance.CheckContainsMoveUnit(cellIndex)) return; for (var i = 1; i <= maxDistance; i++) { var minSteps = i - 1; var maxSteps = i; var cells = map.TerrainGridSystem.CellGetNeighboursWithinRange(cellIndex, minSteps, maxSteps, canCrossCheckType: TGS.CanCrossCheckType.IgnoreCanCrossCheckOnAllCells); foreach (var cell in cells) { if (!CheckCellCanSelect(cell)) continue; if (!PathFinder.CanBasePass(cell, owner)) continue; if (AreaManager.instance.CheckContainsMoveUnit(cell)) continue; // 判断该位置可否攻击目标 var searchArea = AreaManager.instance.attackAreaManager.GetAttackArea(cell, owner.fightData.attackDistance); if (!searchArea.canAttackCells.Contains(enemyCellIndex)) continue; if (maxSteps > 1) { if (CheckPathExits(owner, cell)) { owner.controlData.targetCellIndex = cell; return; } } else { owner.controlData.targetCellIndex = cell; return; } } } // 无处可去 owner.MoveTo(owner.transData.bornCellIndex, true); } catch (Exception e) { DebugUtil.LogError("AIUtils.AvoidEnemy error: {0}", e); } } /// /// 计算当前位置与出生点位置是否超过防守距离 /// public static bool CheckDistanceIsOver(GameUnit owner) { try { if (owner == null) return true; var map = LevelManager.Instance.CurrentLevel.Map; if (map == null) return true; var curPos = owner.transData.cellIndex; var bornPos = owner.unitLevelData.BornPosition; var distance = MapUtils.Distance(map, curPos, bornPos); return owner.unitLevelData.DefensiveDistance < distance; } catch (Exception e) { DebugUtil.LogError("AIUtils.CheckDistanceIsOver error: {0}", e); // 默认超出 return true; } } /// /// 顺时针获取周围第一个能够到达的一圈格子 /// public static int GetCanReachCellAround(Map map, GameUnit owner, int centerIndex, int step = 1) { var cellList = GetAroundCells(centerIndex, step); foreach (var cellIndex in cellList) { var blockData = map.GetBlockData(cellIndex); if (blockData == null) continue; var typeProperty = blockData.GetTerrainTypeProperty(); if (typeProperty == null) continue; if (CheckPathExits(owner, cellIndex)) { return cellIndex; } } return -1; } /// /// 检测是否存在路径 /// public static bool CheckPathExits(GameUnit owner, int cellIndex) { var map = LevelManager.Instance.CurrentLevel.Map; if (owner == null || cellIndex == -1 || map == null) return false; var path = PathFinder.FindPath(map, cellIndex, owner); return path != null && path.Count > 0; } /// /// 设置cellIndex周围的通行级别 /// /// Dic(格子,原来的通行级别) public static Dictionary SetCellCrossLevel(Map map, GameUnit owner, int cellIndex, int step = 1) { if (map == null || owner == null) return null; var cells = new Dictionary(); var cellList = GetAroundCells(cellIndex, step); var crossLevel = owner.commonData.crossLevel + 1; foreach (var cell in cellList) { var blockData = map.GetBlockData(cell); if (blockData == null) continue; map.GetRuntimeBlockProperty(cell, out var data); var oldCrossLevel = data.crossLevel; if (data.crossLevel > crossLevel) continue; data.crossLevel = crossLevel + 1; map.SetRuntimeBlockProperty(cell, data); cells[cell] = oldCrossLevel; //DebugUtil.LogWarning("设置地格{0}的通行级别为:{1}", cell, crossLevel); } return cells; } /// /// 设置cellList通行级别 /// public static void SetCellCrossLevel(Map map, Dictionary cells) { if (map == null) return; foreach (var cell in cells) { var blockData = map.GetBlockData(cell.Key); if (blockData == null) continue; map.GetRuntimeBlockProperty(cell.Key, out var data); data.crossLevel = cell.Value; map.SetRuntimeBlockProperty(cell.Key, data); //DebugUtil.LogError("还原格子:{0}到{1}", cell.Key, cell.Value); } } /// /// 获得周围格子 /// private static List GetAroundCells(int centerIndex, int step = 1) { var cellList = new List(); AroundHelper.GetAround(centerIndex, step, cellList); return cellList; } /// /// 寻找锁敌范围内的敌方npc /// private static Dictionary FindEnemyNpcInSight(GameUnit owner) { try { var enemyNpc = new Dictionary(); var level = LevelManager.Instance.CurrentLevel; if (level == null) return enemyNpc; var map = LevelManager.Instance.CurrentLevel.Map; if (map == null || level.SelfNpcLocalID == null || level.SelfNpcLocalID.Count <= 0) return enemyNpc; var enemyList = GameUnitManager.instance.SearchEnemies(owner); foreach (var enemy in enemyList) { if (enemy.unitLevelData == null) continue; if (level.SelfNpcLocalID.Contains(enemy.unitLevelData.LocalId)) { var distance = MapUtils.Distance(map, enemy.transData.cellIndex, owner.transData.cellIndex); if (distance <= owner.fightData.findEnemyRange) enemyNpc.Add(enemy, distance); } } return enemyNpc; } catch (Exception e) { DebugUtil.LogError("AIUtils.FindEnemyNpcInSight error: {0}", e); return null; } } // -------------------- New -------------------- // #region 寻找敌人 /// /// 寻找视野内的最近敌人 range为-1则为索敌范围 /// public static GameUnit FindNearestTarget(GameUnit owner, int range = -1, Ejob job = Ejob.Job_Other) { try { var inSightDistanceDic = FindEnemiesInRange(owner, range, job); return GetNearestUnit(inSightDistanceDic); } catch (Exception e) { DebugUtil.LogError("AIUtils.FindNearestTarget error: {0}", e); return null; } } /// /// 寻找范围内符合条件的所有敌人 /// public static Dictionary FindEnemiesInRange(GameUnit owner, int range = -1, Ejob job = Ejob.Job_Other, uint targetID = 0) { if (owner == null || range == 0) return null; var enemies = GameUnitManager.instance.SearchEnemies(owner); var filter = new EnemyFilter(owner, range, job, targetID); return AITargetFinder.FindUnits(owner, enemies, filter); } /// /// 获取最近的单位 /// public static GameUnit GetNearestUnit(Dictionary units) { var minDistance = float.MaxValue; GameUnit nearestUnit = null; foreach (var pair in units) { if (minDistance > pair.Value) { minDistance = pair.Value; nearestUnit = pair.Key; } } return nearestUnit; } /// /// 获取更近的攻击来源单位 /// public static GameUnit GetNearestAttackGameUnit(GameUnit owner, GameUnit newUnit, GameUnit unit) { try { if (owner == null || newUnit == null || unit == null) return null; var map = LevelManager.Instance.CurrentLevel.Map; if (map == null) return null; var ownerCellIndex = owner.transData?.cellIndex; var unitCellIndex = unit.transData?.cellIndex; var newUnitCellIndex = newUnit.transData?.cellIndex; if (!ownerCellIndex.HasValue || !unitCellIndex.HasValue || !newUnitCellIndex.HasValue) return null; var distance = MapUtils.Distance(map, ownerCellIndex.Value, unitCellIndex.Value); var newDistance = MapUtils.Distance(map, ownerCellIndex.Value, newUnitCellIndex.Value); return distance <= newDistance ? unit : newUnit; } catch (Exception e) { DebugUtil.LogError("AIUtils.GetNearestGameUnit error: {0}", e); // 异常返回默认单位 return unit; } } #endregion #region 寻找友军 public static GameUnit FindFriendByMonsterID(int id) { foreach (var unit in GameUnitManager.instance.totalUnits.unitList) { if (unit.unitLevelData != null && !unit.statusData.isDead && unit.unitLevelData.monsterId == id) { return unit; } } return null; } /// /// 寻找视野内的最近敌人 range为-1则为索敌范围 /// public static GameUnit FindNearestFriend(GameUnit owner, int range = -1, Ejob job = Ejob.Job_Other) { try { var inSightDistanceDic = FindFriendInRange(owner, range, job); return GetNearestUnit(inSightDistanceDic); } catch (Exception e) { DebugUtil.LogError("AIUtils.FindNearestFriend error: {0}", e); return null; } } /// /// 寻找范围内符合条件的友军 /// public static Dictionary FindFriendInRange(GameUnit owner, int range = -1, Ejob job = Ejob.Job_Other) { if (owner == null || range == 0) return null; var friends = GameUnitManager.instance.SearchFriends(owner); var filter = new FriendFilter(owner, range, job); return AITargetFinder.FindUnits(owner, friends, filter); } /// /// 检测某个地格是否有友军单位 /// public static GameUnit FindFriendByCellIndex(int cellIndex) { var units = AreaManager.instance.GetUnitsByCellIndex(cellIndex); foreach (var unit in units) { if (unit.commonData.troopId == ETroopsId.Enemy) { return unit; } } return null; } #endregion #region 寻找随机目标 public static int FindRandomCell(GameUnit owner, int maxStep = 0) { try { var map = LevelManager.Instance.CurrentLevel?.Map; if (map == null || owner == null) return -1; var cellIndex = owner.transData.cellIndex; if (!AreaManager.instance.CheckContainsMoveUnit(cellIndex)) return -1; var randomCells = new List(); for (var i = 1; i <= maxStep; i++) { var minSteps = i - 1; var maxSteps = i; var cells = map.TerrainGridSystem.CellGetNeighboursWithinRange(cellIndex, minSteps, maxSteps, canCrossCheckType: TGS.CanCrossCheckType.IgnoreCanCrossCheckOnAllCells); foreach (var cell in cells) { if (!CheckCellCanSelect(cell)) continue; if (!PathFinder.CanBasePass(cell, owner)) continue; if (AreaManager.instance.CheckContainsMoveUnit(cell)) continue; if (maxSteps > 1) { if (CheckPathExits(owner, cell)) { randomCells.Add(cell); } } else { randomCells.Add(cell); } } } if (randomCells.Count == 0) return -1; var randomIndex = UnityEngine.Random.Range(0, randomCells.Count); return randomCells[randomIndex]; } catch (Exception e) { DebugUtil.LogError("AIUtils.FindRandomCell error: {0}", e); return -1; } } /// /// 寻找随机单位 /// public static GameUnit FindRandomTarget(GameUnit owner, uint enemy, int range = -1) { try { var targetID = enemy; var inSightDistanceDic = FindEnemiesInRange(owner, range, targetID: targetID); return GetRandomUnit(inSightDistanceDic); } catch (Exception e) { DebugUtil.LogError("AIUtils.FindRandomTarget error: {0}", e); return null; } } /// /// 获取随机单位 /// private static GameUnit GetRandomUnit(Dictionary units) { if (units == null || units.Count == 0) return null; var unitList = units.Keys.ToList(); var randomUnit = unitList[UnityEngine.Random.Range(0, unitList.Count)]; return randomUnit; } #endregion #region 载具相关 /// /// 寻找周围可以到达的格子 (用于载具下人) /// public static int FindCanReachCell(int cellIndex, GameUnit unit, int maxStep = 2) { try { var map = LevelManager.Instance.CurrentLevel?.Map; if (map == null) return -1; for (var i = 1; i <= maxStep; i++) { var minSteps = i - 1; var maxSteps = i; var cells = map.TerrainGridSystem.CellGetNeighboursWithinRange(cellIndex, minSteps, maxSteps, canCrossCheckType: TGS.CanCrossCheckType.IgnoreCanCrossCheckOnAllCells); foreach (var cell in cells) { if (!PathFinder.CanBasePass(cell, unit)) continue; if (AreaManager.instance.CheckContainsMoveUnit(cell)) continue; return cell; } } // 无处可去 return -1; } catch (Exception e) { DebugUtil.LogError("AIUtils.FindCanReachCell error: {0}", e); return -1; } } /// /// 寻找最近的载具 /// public static NormalVehicle FindNearestVehicle(GameUnit owner) { try { var inSightDistanceDic = new Dictionary(); foreach (var unit in GameUnitManager.instance.infightUnits.GetListByTroop(ETroopsId.Enemy)) { if (unit.gameunitType == EGameUnitType.Vehicle) { inSightDistanceDic.Add(unit, GetDistance(owner.transData.cellIndex, unit.transData.cellIndex)); } } var gameUnit = GetNearestUnit(inSightDistanceDic); return gameUnit as NormalVehicle; } catch (Exception e) { DebugUtil.LogError("AIUtils.FindNearestVehicle error: {0}", e); return null; } } #endregion #region 巡逻相关 /// /// 寻找最近的巡逻点位 /// public static int FindNearestPatrolInfoIndex(GameUnit owner, List patrolInfos) { return NearestSearchUtils.FindNearestIndex(owner, patrolInfos, patrolInfo => { var map = LevelManager.Instance.CurrentLevel?.Map; return map?.BlockPosition2TGSCellIndex(patrolInfo.patrolPoint) ?? Constants.INVALID_ID; }); } /// /// 巡逻点位转换为格子索引 /// public static int GetPatrolPointIndex(int patrolIndex, List patrolInfos) { var map = LevelManager.Instance.CurrentLevel.Map; if (map == null || patrolIndex >= patrolInfos.Count) return -1; var patrolInfo = patrolInfos[patrolIndex]; if (patrolInfo == null) return -1; return map.BlockPosition2TGSCellIndex(patrolInfo.patrolPoint); } /// /// 寻找最近的路点点位 /// public static int FindNearestRoadInfoIndex(GameUnit owner, List cells) { return NearestSearchUtils.FindNearestIndex(owner, cells, cellIndex => cellIndex); } /// /// 获取点位等待时间 /// public static float GetPatrolPointWaitTime(int patrolIndex, List patrolInfos) { if (patrolIndex < 0 || patrolIndex >= patrolInfos.Count) return 0; return patrolInfos[patrolIndex]?.waitTime ?? 0; } #endregion #region 防重合 /// /// 避让参数 /// public struct AvoidanceContext { public bool NeedAvoidCheck; public float AvoidCheckTimer; public float CurrentAvoidDelay; } private const float MIN_AVOID_DELAY = 0f; private const float MAX_AVOID_DELAY = 1f; /// /// Update驱动的避让逻辑 /// /// 单位 /// 避让上下文数据结构(ref传入) /// 目标ID public static void TryAvoidOtherUnit(GameUnit owner, ref AvoidanceContext context, uint targetId) { if (IsNeedStop(owner)) return; // 移动中:准备检测避让 if (owner.statusData.isMoveing && !context.NeedAvoidCheck) { context.NeedAvoidCheck = true; context.CurrentAvoidDelay = UnityEngine.Random.Range(MIN_AVOID_DELAY, MAX_AVOID_DELAY); context.AvoidCheckTimer = 0f; } // 移动结束:计时触发检测 if (context.NeedAvoidCheck && !owner.statusData.isMoveing && owner.controlData.targetCellIndex == -1) { context.AvoidCheckTimer += Time.deltaTime; if (context.AvoidCheckTimer >= context.CurrentAvoidDelay) { context.NeedAvoidCheck = false; CheckAreaHasOtherUnit(owner, targetId); } } } /// /// 判断是否有敌人重合 /// private static void CheckAreaHasOtherUnit(GameUnit owner, uint target) { try { if (owner == null || owner.statusData.isMoveing) return; var cellIndex = owner.transData.cellIndex; var units = AreaManager.instance.GetUnitsByCellIndex(cellIndex); var hasOther = false; foreach (var unit in units) { if (unit == owner) continue; if (!unit.commonData.canClaimStandCellIndex) continue; if (unit.statusData.isMoveing) continue; hasOther = true; break; } if (!hasOther) return; if (target == Constants.INVALID_UINT_ID) { MoveToOtherCell(owner); } else { var enemy = GameUnitManager.instance.infightUnits.Search(target); if (enemy == null || enemy.statusData.isDead) return; MoveToCanAttackCell(owner, enemy); } } catch (Exception e) { DebugUtil.LogError("AIUtils.CheckAreaIsOtherEnemyUnit error: {0}", e); } } /// /// 移动至周围可到达格子 /// public static void MoveToOtherCell(GameUnit owner, int centerCell = -1, int maxStep = 2) { try { var map = LevelManager.Instance.CurrentLevel?.Map; if (map == null || owner == null) return; var cellIndex = centerCell == -1 ? owner.transData.cellIndex : centerCell; if (!AreaManager.instance.CheckContainsMoveUnit(cellIndex)) return; for (var i = 1; i <= maxStep; i++) { var minSteps = i - 1; var maxSteps = i; var cells = map.TerrainGridSystem.CellGetNeighboursWithinRange(cellIndex, minSteps, maxSteps, canCrossCheckType: TGS.CanCrossCheckType.IgnoreCanCrossCheckOnAllCells); foreach (var cell in cells) { if (!CheckCellCanSelect(cell)) continue; if (!PathFinder.CanBasePass(cell, owner)) continue; if (AreaManager.instance.CheckContainsMoveUnit(cell)) continue; if (maxSteps > 1) { if (CheckPathExits(owner, cell)) { owner.controlData.targetCellIndex = cell; return; } } else { owner.controlData.targetCellIndex = cell; return; } } } // 无处可去 owner.MoveTo(owner.transData.bornCellIndex, true); } catch (Exception e) { DebugUtil.LogError("AIUtils.MoveOtherCell error: {0}", e); } } /// /// 移动至可以攻击到目标的周围格子 /// private static void MoveToCanAttackCell(GameUnit owner, GameUnit enemy, int maxStep = 2) { try { var map = LevelManager.Instance.CurrentLevel?.Map; if (map == null || owner == null || enemy == null) return; var enemyCellIndex = enemy.transData.cellIndex; var cellIndex = owner.transData.cellIndex; if (!AreaManager.instance.CheckContainsMoveUnit(cellIndex)) return; for (var i = 1; i <= maxStep; i++) { var minSteps = i - 1; var maxSteps = i; var cells = map.TerrainGridSystem.CellGetNeighboursWithinRange(cellIndex, minSteps, maxSteps, canCrossCheckType: TGS.CanCrossCheckType.IgnoreCanCrossCheckOnAllCells); foreach (var cell in cells) { if (!CheckCellCanSelect(cell)) continue; if (!PathFinder.CanBasePass(cell, owner)) continue; if (AreaManager.instance.CheckContainsMoveUnit(cell)) continue; // 判断该位置可否攻击目标 var searchArea = AreaManager.instance.attackAreaManager.GetAttackArea(cell, owner.fightData.attackDistance); if (!searchArea.canAttackCells.Contains(enemyCellIndex)) continue; if (maxSteps > 1) { if (CheckPathExits(owner, cell)) { owner.controlData.targetCellIndex = cell; return; } } else { owner.controlData.targetCellIndex = cell; return; } } } // 无处可去 owner.MoveTo(owner.transData.bornCellIndex, true); } catch (Exception e) { DebugUtil.LogError("AIUtils.AvoidEnemy error: {0}", e); } } #endregion #region Normal /// /// 检测位置是否可到达 /// public static bool PositionCanReach(GameUnit owner, int targetCellIndex) { var map = LevelManager.Instance.CurrentLevel.Map; if (owner == null || targetCellIndex == -1 || map == null) return false; if (!CheckCellCanSelect(targetCellIndex)) return false; var path = PathFinder.FindPath(map, targetCellIndex, owner); return path != null && path.Count > 0; } /// /// 获取距离 /// public static int GetDistance(int cellIndex1, int cellIndex2) { var map = LevelManager.Instance.CurrentLevel.Map; if (map == null) return -1; return MapUtils.Distance(map, cellIndex1, cellIndex2); } /// /// 是否需要停掉AI /// public static bool IsNeedStop(GameUnit owner) { return owner.statusData.isRetreat || owner.statusData.isDead || !owner.statusData.isOnFloor || owner.statusData.isChaos || owner.statusData.isStun || owner.statusData.isLockPos; } /// /// 检测目标是否能被攻击 /// public static bool CheckCanBeTarget(GameUnit owner, GameUnit enemy) { if (owner == null || enemy == null) return false; return enemy.statusData.CheckCanBeTarget(owner, owner.fightData.attackDistance); } /// /// 获取格子世界坐标 /// public static Vector3 GetCellPosFromIndex(int cellIndex) { if (cellIndex == -1) return Vector3.zero; var map = LevelManager.Instance.CurrentLevel.Map; if (map == null) return Vector3.zero; return map.TGSCellIndex2WorldPosition(cellIndex); } /// /// 检测地格是否可选 /// private static bool CheckCellCanSelect(int cellIndex) { var map = LevelManager.Instance.CurrentLevel.Map; if (map == null) return false; return MapUtils.GetTypeProperty(map, cellIndex) != null && MapUtils.GetTypeProperty(map, cellIndex).selectable; } /// /// 检测地格是否可选 /// public static bool CheckCellCanSelect(Vector2Int cellPos) { var map = LevelManager.Instance.CurrentLevel.Map; if (map == null) return false; var cell = map.BlockPosition2TGSCellIndex(cellPos); return MapUtils.GetTypeProperty(map, cell) != null && MapUtils.GetTypeProperty(map, cell).selectable; } /// /// 范围限制 /// public static int ClampCoord(int value, int min, int max) => Mathf.Clamp(value, min, max); #endregion } }