using System; using Framework; using System.Linq; using Gameplay.Unit; using Gameplay.Area; using Gameplay.Level; using cfg.CharacterCfg; using Gameplay.Character; using Gameplay.Pool; using System.Collections.Generic; namespace Gameplay.AI { public static partial class AIUtils { /// /// 对象池 - 用于缓存单位距离字典 /// private static readonly Dictionary UnitsDistanceCache = new (64); /// /// 临时列表,用于避免在 GetNearestUnit/GetRandomUnit 中创建新列表 /// private static readonly List> TempPairList = new (64); /// /// 通过GUID获取单位 /// public static GameUnit FindUnit(uint id) { if (GameUnitManager.instance.deadUnits.Contains(id)) return null; return GameUnitManager.instance.infightUnits.Contains(id) ? GameUnitManager.instance.infightUnits.Search(id) : null; } /// /// 获取符合条件的单位及距离 /// /// 自身 /// 需要筛选的对象 /// 条件 /// private static Dictionary FindUnits(GameUnit owner, List candidates, IAITargetFilter filter) { // 清空临时字典以便重用 UnitsDistanceCache.Clear(); var ownerCell = owner.transData?.cellIndex; if (!ownerCell.HasValue) return UnitsDistanceCache; foreach (var unit in candidates) { var cell = unit.transData?.cellIndex; if (!cell.HasValue) continue; if (filter.IsValid(unit)) { int distance = GetDistance(ownerCell.Value, cell.Value); UnitsDistanceCache[unit] = distance; } } return UnitsDistanceCache; } #region 寻找敌人 /// /// 寻找视野内的最近敌人 /// /// 自身 /// 指定范围 -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); // 使用对象池获取EnemyFilter var filter = ObjPoolManager.instance.Get(); filter.Init(owner, range, job, targetID); var result = FindUnits(owner, enemies, filter); // 使用完毕后返回对象池 ObjPoolManager.instance.Return(filter); // 归还临时列表 GameUnitManager.instance.ReturnTempList(enemies); return result; } /// /// 获取最近的单位 /// public static GameUnit GetNearestUnit(Dictionary units) { if (units == null || units.Count == 0) return null; 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 寻找友军 /// /// 通过MonsterID寻找友军 只返回第一个Monster /// 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; } /// /// 寻找视野内的最近友军 /// /// 自身 /// 指定距离 -1为锁敌距离 /// 指定职业 public static GameUnit FindNearestFriend(GameUnit owner, int range = -1, Ejob job = Ejob.Job_Other) { try { var inSightDistanceDic = FindFriendsWithDistance(owner, range, job); return GetNearestUnit(inSightDistanceDic); } catch (Exception e) { DebugUtil.LogError("AIUtils.FindNearestFriend error: {0}", e); return null; } } /// /// 寻找锁敌范围内的友军列表 /// public static List FindFriendsInSightDistance(GameUnit owner) { try { var friends = FindFriendsWithDistance(owner); if (friends == null || friends.Count == 0) return new List(); // 避免创建新列表,使用单位字典的键集合 var result = new List(friends.Keys); return result; } catch (Exception e) { DebugUtil.LogError("AIUtils.FindFriendsInSightDistance error: {0}", e); return null; } } /// /// 寻找符合条件的友军及距离字典 /// public static Dictionary FindFriendsWithDistance(GameUnit owner, int range = -1, Ejob job = Ejob.Job_Other) { if (owner == null || range == 0) return null; var friends = GameUnitManager.instance.SearchFriends(owner); // 使用对象池获取FriendFilter var filter = ObjPoolManager.instance.Get(); filter.Init(owner, range, job); var result = FindUnits(owner, friends, filter); // 使用完毕后返回对象池 ObjPoolManager.instance.Return(filter); // 归还临时列表 GameUnitManager.instance.ReturnTempList(friends); return result; } /// /// 检测某个地格是否有友军单位 /// 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; // 使用复用的临时列表避免创建新列表 TempPairList.Clear(); foreach (var pair in units) { TempPairList.Add(new KeyValuePair(pair.Key, pair.Value)); } if (TempPairList.Count == 0) return null; var randomIndex = UnityEngine.Random.Range(0, TempPairList.Count); return TempPairList[randomIndex].Key; } #endregion #region 组内单位 寻找 判断 public static bool GroupTargetInRange(GameUnit owner, List group) { var inRange = false; var groupFriends = FindGroupUnits(owner, group); foreach (var groupFriend in groupFriends) { var targetID = groupFriend.unitLevelData.AIBattleInfo.Value.targetID; if (targetID == Constants.INVALID_UINT_ID) continue; var target = GameUnitManager.instance.infightUnits.Search(targetID); var distance = GetDistance(owner.transData.cellIndex, target.transData.cellIndex); if (distance <= groupFriend.fightData.trackRange) { inRange = true; break; } } return inRange; } public static List FindGroupUnits(GameUnit owner, List group) { var groupUnits = new List(); if (owner == null || group == null || group.Count == 0) return groupUnits; var friends = GameUnitManager.instance.SearchFriends(owner); foreach (var friend in friends) { if (friend.unitLevelData == null || friend.unitLevelData.AIBattleInfo == null) continue; var unitGroups = friend.unitLevelData.AIBattleInfo.Value.groupInfo; if (unitGroups == null || unitGroups.Count <= 0) continue; // 检查当前单位的组ID列表与传入的组ID列表是否有交集 foreach (var groupId in unitGroups) { if (group.Contains(groupId)) { groupUnits.Add(friend); break; // 找到一个匹配就可以添加该单位,无需继续检查其他组ID } } } return groupUnits; } #endregion } }