using System; using Framework; using Gameplay.Area; using Gameplay.Unit; using Gameplay.Level; using Gameplay.Unit.Data; using System.Collections.Generic; using static Gameplay.Level.LevelData; namespace Gameplay.AI { public static class AIUtils { private static List inSightEnemies = new List(16); private static Dictionary inSightDistanceList = new Dictionary(16); public static GameUnit FindNearestEnemyInSightDistance(GameUnit owner) { if (owner == null) return null; var map = LevelManager.Instance.CurrentLevel.Map; if (map == null) return null; inSightEnemies.Clear(); inSightDistanceList.Clear(); GameUnitManager.instance.characterManager.SearchEnemies(owner, inSightEnemies); var ownerCellIndex = owner.transData?.cellIndex; for (var i = 0; i < inSightEnemies.Count; i++) { var enemy = inSightEnemies[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) { 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; } } public static GameUnit FindNearestEnemyInShootRange(GameUnit owner) { if (owner == null) return null; var map = LevelManager.Instance.CurrentLevel.Map; if (map == null) return null; inSightEnemies.Clear(); inSightDistanceList.Clear(); GameUnitManager.instance.characterManager.SearchEnemies(owner, inSightEnemies); var ownerCellIndex = owner.transData?.cellIndex; for (var i = 0; i < inSightEnemies.Count; i++) { var enemy = inSightEnemies[i]; if (enemy == null) { 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.normalAttackDistance) { inSightDistanceList.Add(enemy, distance); } } if (inSightDistanceList.Count <= 0) { return null; } else { owner.statusData.isAttackActive = true; var minDistance = float.MaxValue; GameUnit nearestEnemy = null; foreach (var pair in inSightDistanceList) { if (minDistance > pair.Value) { minDistance = pair.Value; nearestEnemy = pair.Key; } } return nearestEnemy; } } private static List enemies = new List(16); private static List inAttackEnemies = new List(16); public static List FindEnemiesInAttackDistance(GameUnit owner) { if (owner == null) return null; var map = LevelManager.Instance.CurrentLevel.Map; if (map == null) return null; enemies.Clear(); inAttackEnemies.Clear(); GameUnitManager.instance.characterManager.SearchEnemies(owner, enemies); var ownerCellIndex = owner.transData?.cellIndex; for (int i = 0; i < enemies.Count; i++) { var enemy = enemies[i]; if (enemy == null || enemy.GetID() == owner.GetID()) { 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.attackDistance) { inAttackEnemies.Add(enemy); } } return inAttackEnemies; } private static List allFriends = new List(16); private static List friendsInSight = new List(16); public static List FindFriendsInSightDistance(GameUnit owner) { if (owner == null) return null; var map = LevelManager.Instance.CurrentLevel.Map; if (map == null) return null; allFriends.Clear(); friendsInSight.Clear(); GameUnitManager.instance.characterManager.SearchFriends(owner, allFriends); var ownerCellIndex = owner.transData?.cellIndex; for (var i = 0; i < allFriends.Count; i++) { var friend = allFriends[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; } public static bool IsTargetInSightDistance(GameUnit owner, GameUnit target) { var map = LevelManager.Instance.CurrentLevel.Map; if (map == null) return false; var ownerCellIndex = owner.transData?.cellIndex; var unitCellIndex = target.transData?.cellIndex; if (!ownerCellIndex.HasValue || !unitCellIndex.HasValue) return false; var distance = MapUtils.Distance(map, ownerCellIndex.Value, unitCellIndex.Value); if (distance <= owner.fightData.findEnemyRange) { return true; } return false; } public static int GetTargetInSightDistance(GameUnit owner, GameUnit target) { var map = LevelManager.Instance.CurrentLevel.Map; if (map == null) return -1; var ownerCellIndex = owner.transData?.cellIndex; var unitCellIndex = target.transData?.cellIndex; if (!ownerCellIndex.HasValue || !unitCellIndex.HasValue) return -1; var distance = MapUtils.Distance(map, ownerCellIndex.Value, unitCellIndex.Value); return distance; } public static GameUnit GetNearestGameUnit(GameUnit owner, GameUnit newUnit, GameUnit unit) { 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; } private static Dictionary patrolDistanceList = new Dictionary(64); public static int FindNearestPointInPatrolInfo(GameUnit owner, List patrolInfos) { 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; } public static int GetPatrolPointIndexFromVector2Int(Map map, int patrolIndex, List patrolInfos) { if (map == null || patrolIndex >= patrolInfos.Count) return -1; var patrolInfo = patrolInfos[patrolIndex]; if (patrolInfo == null) return -1; return map.BlockPosition2TGSCellIndex(patrolInfo.patrolPoint); } public static bool IsNeedStop(GameUnit owner) { return owner.statusData.isOnVehicle || owner.statusData.isChaos || owner.statusData.isStun || owner.statusData.isLockPos || owner.statusData.isRetreat || owner.statusData.isDead; } public static bool AINeedStopUpdate(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) { 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; } else { var target = FindNearestEnemyInShootRange(owner); if (target != null) { owner.controlData.targetEnemy = target; owner.statusData.isAttackActive = true; } } } public static bool MoveTo(GameUnit owner, int cellIndex, bool cancelFollow = true) { 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 = map.MapData.GetBlockData(cellIndex).GetTerrainTypeProperty(); if (blockData == null) return false; if (!blockData.selectable) return false; owner.MoveTo(cellIndex, cancelFollow); return true; } /// /// AI 移动向敌人并检查 /// public static void CheckAndMove(GameUnit owner, int cellIndex, bool cancelFollow = true) { // DebugUtil.LogError("开始向:{0}移动", cellIndex); if (!MoveTo(owner, cellIndex, cancelFollow)) return; if (owner.gameunitType != EGameUnitType.Character && owner.gameunitType != EGameUnitType.Vehicle) return; var units = AreaManager.instance.GetUnitsByCellIndex(cellIndex); for (int i = 0; i < units.Count; i++) { var unit = units[i]; if (unit.commonData.troopId == owner.commonData.troopId) { /*if (owner.gameunitType == EGameUnitType.Vehicle) { // 载具不能上载具 return; } // 点击的己方单位, 这里必然是载具 var vehicle = unit as NormalVehicle; if (vehicle == null) { DebugUtil.LogError("不是载具"); return; } if (vehicle.CheckCanUp(owner)) { owner.controlData.markVehicle = vehicle; } return;*/ } else { // 如果是敌人, 则设置敌人目标 if (unit.statusData.CheckCanBeTarget(owner, -1)) { owner.controlData.markEnemy = unit; owner.controlData.forceUpdateTarget = true; return; } } } // 走到这里,说明没有目标,清空标记 owner.controlData.markVehicle = null; owner.controlData.markEnemy = null; } } }