2023-10-19 15:00:19 +08:00
|
|
|
|
using System.Collections;
|
|
|
|
|
|
using System.Collections.Generic;
|
2023-08-22 19:08:45 +08:00
|
|
|
|
using System.Text;
|
2024-09-23 15:05:34 +08:00
|
|
|
|
using AOT.PostProcess.BlackArea;
|
2024-07-11 14:32:53 +08:00
|
|
|
|
using Gameplay.Area;
|
|
|
|
|
|
using Gameplay.Character;
|
2024-09-26 16:31:04 +08:00
|
|
|
|
using Gameplay.Common;
|
2024-07-11 14:32:53 +08:00
|
|
|
|
using Gameplay.Level;
|
|
|
|
|
|
using Gameplay.PostProcess.BlackArea;
|
|
|
|
|
|
using Gameplay.Unit;
|
2023-08-22 19:08:45 +08:00
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
using static Gameplay.Map;
|
|
|
|
|
|
|
|
|
|
|
|
namespace Gameplay
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
public static class PathFinder
|
|
|
|
|
|
{
|
2024-07-11 14:32:53 +08:00
|
|
|
|
|
|
|
|
|
|
private static List<int> _cacheChangedCellIndexs = new List<int>();
|
|
|
|
|
|
|
|
|
|
|
|
private static void _RuntimeMarkMapCrossState(GameUnit moveUnit)
|
|
|
|
|
|
{
|
|
|
|
|
|
var map = LevelManager.Instance.CurrentLevel.Map;
|
|
|
|
|
|
// 找到所有的单位
|
|
|
|
|
|
var allUnits = GameUnitManager.instance.infightUnits.unitList;
|
|
|
|
|
|
for (int i = 0; i < allUnits.Count; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
var unit = allUnits[i];
|
2024-12-09 19:14:43 +08:00
|
|
|
|
if (unit.statusData.isOnVehicle)
|
2024-07-11 14:32:53 +08:00
|
|
|
|
{
|
2024-12-09 19:14:43 +08:00
|
|
|
|
// 在载具上的单位不需要设置
|
2024-07-11 14:32:53 +08:00
|
|
|
|
continue;
|
|
|
|
|
|
}
|
2024-12-09 19:14:43 +08:00
|
|
|
|
if (unit.transData.cellIndex == moveUnit.transData.cellIndex)
|
2024-07-11 14:32:53 +08:00
|
|
|
|
{
|
2024-12-09 19:14:43 +08:00
|
|
|
|
// 重叠时特殊处理
|
2024-07-11 14:32:53 +08:00
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
var cellIndex = unit.transData.cellIndex;
|
|
|
|
|
|
var unitStandLevel = unit.commonData.standLevel;
|
|
|
|
|
|
map.GetRuntimeBlockProperty(cellIndex, out RuntimeBlockProperty runtimeBlockProperty);
|
|
|
|
|
|
if (unitStandLevel > runtimeBlockProperty.crossLevel)
|
|
|
|
|
|
{
|
|
|
|
|
|
runtimeBlockProperty.crossLevel = unitStandLevel;
|
|
|
|
|
|
map.SetRuntimeBlockProperty(cellIndex, runtimeBlockProperty);
|
|
|
|
|
|
_cacheChangedCellIndexs.Add(cellIndex);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-10-23 11:54:52 +08:00
|
|
|
|
// if (moveUnit.commonData.troopId == ETroopsId.Self)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// // 如果是己方,需要将所有未照亮的格子设置为不可通行
|
|
|
|
|
|
// var allLightPoints = (BlackAreaManager.instance as BlackAreaManagerImpl).pointList;
|
|
|
|
|
|
// for (int i = 0; i < allLightPoints.Count; i++)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// var point = allLightPoints[i];
|
|
|
|
|
|
// if (point.isLight) continue;
|
|
|
|
|
|
// var cellIndex = point.cellIndex;
|
|
|
|
|
|
// map.GetRuntimeBlockProperty(cellIndex, out RuntimeBlockProperty runtimeBlockProperty);
|
|
|
|
|
|
// runtimeBlockProperty.crossLevel = int.MaxValue;
|
|
|
|
|
|
// map.SetRuntimeBlockProperty(cellIndex, runtimeBlockProperty);
|
|
|
|
|
|
// _cacheChangedCellIndexs.Add(cellIndex);
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
2024-07-11 14:32:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static void _RuntimeRecoverMapCrossState()
|
|
|
|
|
|
{
|
|
|
|
|
|
var map = LevelManager.Instance.CurrentLevel.Map;
|
|
|
|
|
|
for (int i = 0; i < _cacheChangedCellIndexs.Count; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
var cellIndex = _cacheChangedCellIndexs[i];
|
|
|
|
|
|
map.GetRuntimeBlockProperty(cellIndex, out RuntimeBlockProperty runtimeBlockProperty);
|
|
|
|
|
|
var mapData = map.GetBlockData(cellIndex);
|
|
|
|
|
|
runtimeBlockProperty.crossLevel = mapData.GetTerrainTypeProperty().crossLevel;
|
|
|
|
|
|
map.SetRuntimeBlockProperty(cellIndex, runtimeBlockProperty);
|
|
|
|
|
|
}
|
|
|
|
|
|
_cacheChangedCellIndexs.Clear();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static bool CanPass(int cellIndex,
|
|
|
|
|
|
GameUnit moveUnit)
|
|
|
|
|
|
{
|
2024-09-30 18:06:04 +08:00
|
|
|
|
if (!CanBasePass(cellIndex, moveUnit))
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2024-07-11 14:32:53 +08:00
|
|
|
|
var crossLevel = moveUnit.commonData.crossLevel;
|
|
|
|
|
|
// 额外判断当前格子是否有单位
|
|
|
|
|
|
var units = AreaManager.instance.GetUnitsByCellIndex(cellIndex);
|
|
|
|
|
|
for (int i = 0; i < units.Count; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
var unit = units[i];
|
|
|
|
|
|
if (unit == moveUnit) continue;
|
|
|
|
|
|
if (unit.commonData.standLevel >= crossLevel) return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
2024-08-14 20:00:00 +08:00
|
|
|
|
|
2024-09-30 18:06:04 +08:00
|
|
|
|
public static bool CanBasePass(int cellIndex,
|
|
|
|
|
|
GameUnit moveUnit)
|
|
|
|
|
|
{
|
|
|
|
|
|
var map = LevelManager.Instance.CurrentLevel.Map;
|
|
|
|
|
|
var crossLevel = moveUnit.commonData.crossLevel;
|
|
|
|
|
|
map.GetRuntimeBlockProperty(cellIndex, out var runtimeBlockProperty);
|
2024-11-07 15:05:36 +08:00
|
|
|
|
if (!runtimeBlockProperty.selectable) return false;
|
2024-09-30 18:06:04 +08:00
|
|
|
|
if (crossLevel <= runtimeBlockProperty.crossLevel) return false;
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-08-14 20:00:00 +08:00
|
|
|
|
private static bool _CheckEndCanPass(int to,
|
|
|
|
|
|
GameUnit moveUnit)
|
|
|
|
|
|
{
|
|
|
|
|
|
var map = LevelManager.Instance.CurrentLevel.Map;
|
|
|
|
|
|
var crossLevel = moveUnit.commonData.crossLevel;
|
|
|
|
|
|
map.GetRuntimeBlockProperty(to, out var runtimeBlockProperty);
|
2024-11-07 15:05:36 +08:00
|
|
|
|
if (!runtimeBlockProperty.selectable) return false;
|
2024-08-14 20:00:00 +08:00
|
|
|
|
if (crossLevel <= runtimeBlockProperty.crossLevel) return false;
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
2023-08-22 19:08:45 +08:00
|
|
|
|
|
2023-10-19 15:00:19 +08:00
|
|
|
|
public static List<int> FindPath(Map map,
|
|
|
|
|
|
int to,
|
2024-07-11 14:32:53 +08:00
|
|
|
|
GameUnit moveUnit)
|
2023-08-22 19:08:45 +08:00
|
|
|
|
{
|
2024-07-11 14:32:53 +08:00
|
|
|
|
var moveLevel = moveUnit.commonData.crossLevel;
|
|
|
|
|
|
var from = moveUnit.transData.cellIndex;
|
2023-08-22 19:08:45 +08:00
|
|
|
|
var result = new List<int>();
|
|
|
|
|
|
if (from == to)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 同一个格子
|
|
|
|
|
|
result.Add(to);
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var canReach = true;
|
|
|
|
|
|
var mapData = map.GetBlockData(to);
|
2023-12-14 18:25:52 +08:00
|
|
|
|
if (mapData == null)
|
|
|
|
|
|
{
|
2024-07-11 14:32:53 +08:00
|
|
|
|
DebugUtil.LogError("FindPath: mapData is null, to: " + to);
|
2023-12-14 18:25:52 +08:00
|
|
|
|
return result;
|
|
|
|
|
|
}
|
2024-07-11 14:32:53 +08:00
|
|
|
|
|
2024-08-14 20:00:00 +08:00
|
|
|
|
if (!_CheckEndCanPass(to, moveUnit))
|
2023-08-22 19:08:45 +08:00
|
|
|
|
{
|
|
|
|
|
|
// 如果终点不可通行,直接走无法走通的逻辑
|
2024-07-11 14:32:53 +08:00
|
|
|
|
// 地形层面的不可通行
|
2023-08-22 19:08:45 +08:00
|
|
|
|
canReach = false;
|
|
|
|
|
|
}
|
2024-08-14 20:00:00 +08:00
|
|
|
|
|
|
|
|
|
|
_RuntimeMarkMapCrossState(moveUnit);
|
2023-08-22 19:08:45 +08:00
|
|
|
|
|
|
|
|
|
|
if (canReach)
|
|
|
|
|
|
{
|
2024-12-09 19:14:43 +08:00
|
|
|
|
map.GetRuntimeBlockProperty(to, out var toData);
|
2023-08-22 19:08:45 +08:00
|
|
|
|
MapUtils.ForceSetCanCross(true, ref toData);
|
|
|
|
|
|
map.SetRuntimeBlockProperty(to, toData);
|
2024-07-11 14:32:53 +08:00
|
|
|
|
_cacheChangedCellIndexs.Add(to);
|
2023-08-22 19:08:45 +08:00
|
|
|
|
result = map.TerrainGridSystem.FindPath(from, to, moveLevel);
|
|
|
|
|
|
}
|
2023-10-19 15:00:19 +08:00
|
|
|
|
|
2023-08-22 19:08:45 +08:00
|
|
|
|
// 无法直接走通
|
2024-07-11 14:32:53 +08:00
|
|
|
|
if (!_IsPathExist(result))
|
2023-08-22 19:08:45 +08:00
|
|
|
|
{
|
|
|
|
|
|
var cacheFrom = from;
|
2024-03-28 13:02:59 +08:00
|
|
|
|
var deepSearch = _ProcessCannotFindPath(map, cacheFrom, to, result, moveLevel);
|
2023-08-22 19:08:45 +08:00
|
|
|
|
while (deepSearch)
|
|
|
|
|
|
{
|
|
|
|
|
|
cacheFrom = result[^1];
|
2024-03-28 13:02:59 +08:00
|
|
|
|
deepSearch = _ProcessCannotFindPath(map, cacheFrom, to, result, moveLevel);
|
2023-08-22 19:08:45 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-08-15 15:28:20 +08:00
|
|
|
|
if (result.Count == 1 && !CanPass(to, moveUnit))
|
2023-08-22 19:08:45 +08:00
|
|
|
|
{
|
|
|
|
|
|
// 只有一格 且下一格子不可通行,则无法到达
|
|
|
|
|
|
result.Clear();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-09-26 16:31:04 +08:00
|
|
|
|
if (CodeDefine.ENABLE_FIGHT_NORMAL_ATTACK_LOG)
|
2023-08-22 19:08:45 +08:00
|
|
|
|
{
|
2023-10-19 15:00:19 +08:00
|
|
|
|
var stringBuilder = new StringBuilder();
|
|
|
|
|
|
stringBuilder.Append("FindPath: ");
|
|
|
|
|
|
stringBuilder.Append(from);
|
|
|
|
|
|
stringBuilder.Append(" -> ");
|
|
|
|
|
|
stringBuilder.Append(to);
|
|
|
|
|
|
stringBuilder.Append(" : ");
|
|
|
|
|
|
for (int i = 0; i < result.Count; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
stringBuilder.Append(result[i]);
|
|
|
|
|
|
stringBuilder.Append(" ");
|
|
|
|
|
|
}
|
|
|
|
|
|
DebugUtil.Log(stringBuilder);
|
2023-08-22 19:08:45 +08:00
|
|
|
|
}
|
2023-10-19 15:00:19 +08:00
|
|
|
|
|
2024-07-11 14:32:53 +08:00
|
|
|
|
_RuntimeRecoverMapCrossState();
|
2023-08-22 19:08:45 +08:00
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-10-19 15:00:19 +08:00
|
|
|
|
private static bool _ProcessCannotFindPath(Map map,
|
|
|
|
|
|
int from,
|
|
|
|
|
|
int to,
|
2024-03-28 13:02:59 +08:00
|
|
|
|
ICollection<int> pathList,
|
|
|
|
|
|
int moveLevel)
|
2023-08-22 19:08:45 +08:00
|
|
|
|
{
|
2024-03-28 13:02:59 +08:00
|
|
|
|
|
|
|
|
|
|
// 如果两个格子相邻,则直接返回
|
|
|
|
|
|
var distanceToNow = map.TerrainGridSystem.CellGetHexagonDistance(from, to);
|
|
|
|
|
|
if (distanceToNow <= 1)
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-08-22 19:08:45 +08:00
|
|
|
|
// 无法到达
|
|
|
|
|
|
// 获得附近一圈的格子
|
2024-10-22 12:30:04 +08:00
|
|
|
|
var nearByCells = AreaManager.instance.GetCellIndexsAround(from, 1, false);
|
2023-08-22 19:08:45 +08:00
|
|
|
|
if (nearByCells == null || nearByCells.Count <= 0) return false;
|
|
|
|
|
|
// 取最近的格子
|
|
|
|
|
|
int closestCell = -1;
|
|
|
|
|
|
var selfPos = map.TGSCellIndex2WorldPosition(from);
|
|
|
|
|
|
var targetPos = map.TGSCellIndex2WorldPosition(to);
|
2024-03-28 13:41:51 +08:00
|
|
|
|
var minDistance = Vector3.Distance(selfPos, targetPos) - 0.5f;
|
2023-08-22 19:08:45 +08:00
|
|
|
|
for (int i = 0; i < nearByCells.Count; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
var cellIndex = nearByCells[i];
|
2024-03-28 13:02:59 +08:00
|
|
|
|
|
2024-03-28 13:29:32 +08:00
|
|
|
|
// 不走回头路
|
|
|
|
|
|
if (pathList.Contains(cellIndex))
|
|
|
|
|
|
{
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-03-28 13:02:59 +08:00
|
|
|
|
// 判断是否可通行
|
2024-07-11 14:32:53 +08:00
|
|
|
|
map.GetRuntimeBlockProperty(cellIndex, out var toData);
|
2024-03-28 13:02:59 +08:00
|
|
|
|
if (!MapUtils.CanPass(moveLevel, toData))
|
|
|
|
|
|
{
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-08-22 19:08:45 +08:00
|
|
|
|
var newPos = map.TGSCellIndex2WorldPosition(cellIndex);
|
|
|
|
|
|
var distance = Vector3.Distance(targetPos, newPos);
|
|
|
|
|
|
|
|
|
|
|
|
if (distance < minDistance)
|
|
|
|
|
|
{
|
|
|
|
|
|
minDistance = distance;
|
|
|
|
|
|
closestCell = cellIndex;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (closestCell != -1)
|
|
|
|
|
|
{
|
|
|
|
|
|
pathList.Add(closestCell);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-07-11 14:32:53 +08:00
|
|
|
|
private static bool _IsPathExist(ICollection pathList)
|
2023-08-22 19:08:45 +08:00
|
|
|
|
{
|
|
|
|
|
|
return !(pathList == null || pathList.Count <= 0);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-12-10 16:09:16 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// !!! 该方法极其费性能,慎用 !!!
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="owner"></param>
|
|
|
|
|
|
public static void AvoidRepeat(GameUnit owner)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!owner.commonData.canControl)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 只判断可控制单位
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
var units = AreaManager.instance.GetUnitsByCellIndex(owner.transData.cellIndex);
|
|
|
|
|
|
var hasOther = false;
|
|
|
|
|
|
for (int i = 0; i < units.Count; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
var unit = units[i];
|
|
|
|
|
|
if (unit == owner)
|
|
|
|
|
|
{
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!unit.commonData.canClaimStandCellIndex)
|
|
|
|
|
|
{
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (unit.statusData.isMoveing)
|
|
|
|
|
|
{
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
2024-12-11 13:48:56 +08:00
|
|
|
|
// TODO: 目前实测AI并不会自动避让
|
|
|
|
|
|
// if (!unit.commonData.canControl)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// // AI会自动避让,不需要处理
|
|
|
|
|
|
// continue;
|
|
|
|
|
|
// }
|
2024-12-10 16:09:16 +08:00
|
|
|
|
hasOther = true;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (hasOther)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (owner.controlData.targetEnemy != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
_MoveAnyOtherCanAttackEnemy(owner);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
_MoveAnyOtherPoint(owner);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static void _MoveAnyOtherPoint(GameUnit owner)
|
|
|
|
|
|
{
|
|
|
|
|
|
var searchCellIndex = AreaManager.instance.SearchNearCanClaimCellIndex(owner);
|
|
|
|
|
|
if (searchCellIndex == -1 || searchCellIndex == owner.transData.cellIndex) return;
|
|
|
|
|
|
owner.controlData.targetCellIndex = searchCellIndex;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static void _MoveAnyOtherCanAttackEnemy(GameUnit owner)
|
|
|
|
|
|
{
|
|
|
|
|
|
var searchIndex = AreaManager.instance.SearchNearCanClaimCellIndexWithAttack(owner);
|
|
|
|
|
|
if (searchIndex == -1 || searchIndex == owner.transData.cellIndex) return;
|
|
|
|
|
|
owner.controlData.targetCellIndex = searchIndex;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-08-22 19:08:45 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|