331 lines
12 KiB
C#
331 lines
12 KiB
C#
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<GameUnit> inSightEnemies = new List<GameUnit>();
|
|
private static Dictionary<GameUnit, int> inSightDistanceList = new Dictionary<GameUnit, int>();
|
|
|
|
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)
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
|
|
private static List<GameUnit> enemies = new List<GameUnit>();
|
|
private static List<GameUnit> inAttackEnemies = new List<GameUnit>();
|
|
|
|
public static List<GameUnit> 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<GameUnit> allFriends = new List<GameUnit>();
|
|
private static List<GameUnit> friendsInSight = new List<GameUnit>();
|
|
|
|
public static List<GameUnit> 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<int, int> patrolDistanceList = new Dictionary<int, int>();
|
|
|
|
public static int FindNearestPointInPatrolInfo(GameUnit owner, List<PatrolInfo> 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 bool IsNeedStop(GameUnit owner)
|
|
{
|
|
return owner.statusData.isOnVehicle || owner.statusData.isChaos || owner.statusData.isStun
|
|
|| owner.statusData.isLockPos || owner.statusData.isRetreat;
|
|
}
|
|
|
|
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;
|
|
|
|
var tempInSightEnemies = new List<GameUnit>();
|
|
GameUnitManager.instance.characterManager.SearchEnemies(owner, tempInSightEnemies);
|
|
if (tempInSightEnemies.Count <= 0) return;
|
|
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.findEnemyRange)
|
|
{
|
|
owner.statusData.isAttackActive = true;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// AI检查并移动
|
|
/// </summary>
|
|
public static void CheckAndMove(GameUnit owner, int cellIndex, bool cancelFollow = true)
|
|
{
|
|
if (owner == null || cellIndex == -1) return;
|
|
//if (owner.statusData.isMoveing) return;
|
|
owner.MoveTo(cellIndex, cancelFollow);
|
|
|
|
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;
|
|
}
|
|
}
|
|
} |