NLDClient-yudde/ProjectNLD/Assets/Code/Scripts/Gameplay/AI/Utils/AIUtils.FindUnit.cs

300 lines
10 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using System;
using Framework;
using System.Linq;
using Gameplay.Unit;
using Gameplay.Area;
using Gameplay.Level;
using cfg.CharacterCfg;
using Gameplay.Character;
using System.Collections.Generic;
namespace Gameplay.AI
{
public static partial class AIUtils
{
#region 寻找敌人
/// <summary>
/// 寻找视野内的最近敌人 range为-1则为索敌范围
/// </summary>
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;
}
}
/// <summary>
/// 寻找范围内符合条件的所有敌人
/// </summary>
public static Dictionary<GameUnit, int> 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);
}
/// <summary>
/// 获取最近的单位
/// </summary>
public static GameUnit GetNearestUnit(Dictionary<GameUnit, int> 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;
}
/// <summary>
/// 获取更近的攻击来源单位
/// </summary>
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 寻找友军
/// <summary>
/// 通过MonsterID寻找友军 只返回第一个Monster
/// </summary>
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;
}
/// <summary>
/// 寻找视野内的最近敌人 range为-1则为索敌范围
/// </summary>
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;
}
}
/// <summary>
/// 寻找范围内符合条件的友军
/// </summary>
public static Dictionary<GameUnit, int> 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);
}
/// <summary>
/// 检测某个地格是否有友军单位
/// </summary>
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<int>();
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;
}
}
/// <summary>
/// 寻找随机单位
/// </summary>
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;
}
}
/// <summary>
/// 获取随机单位
/// </summary>
private static GameUnit GetRandomUnit(Dictionary<GameUnit, int> 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 bool GroupTargetInRange(GameUnit owner, List<int> 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<GameUnit> FindGroupUnits(GameUnit owner, List<int> group)
{
var groupUnits = new List<GameUnit>();
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
}
}