NLDClient-yudde/ProjectNLD/Assets/Code/Scripts/Gameplay/Area/Path/PathFinder.cs

173 lines
5.4 KiB
C#

using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using static Gameplay.Map;
namespace Gameplay
{
public static class PathFinder
{
public static List<int> FindPath(Map map,
int from,
int to,
int moveLevel)
{
var result = new List<int>();
if (from == to)
{
// 同一个格子
result.Add(to);
return result;
}
var canReach = true;
var mapData = map.GetBlockData(to);
if (mapData == null)
{
canReach = false;
return result;
}
if (!MapUtils.CanPass(moveLevel, mapData.GetTerrainTypeProperty()))
{
// 如果终点不可通行,直接走无法走通的逻辑
canReach = false;
}
var toData = default(RuntimeBlockProperty);
var oldCrossLevelTo = 0;
// 将自己所在点和目标所在点临时设置为可通行
map.GetRuntimeBlockProperty(from, out RuntimeBlockProperty fromData);
var oldCrossLevelFrom = fromData.crossLevel;
MapUtils.ForceSetCanCross(true, ref fromData);
map.SetRuntimeBlockProperty(from, fromData);
if (canReach)
{
map.GetRuntimeBlockProperty(to, out toData);
oldCrossLevelTo = toData.crossLevel;
MapUtils.ForceSetCanCross(true, ref toData);
map.SetRuntimeBlockProperty(to, toData);
result = map.TerrainGridSystem.FindPath(from, to, moveLevel);
}
// 无法直接走通
if (!_IsFathExist(result))
{
var cacheFrom = from;
var deepSearch = _ProcessCannotFindPath(map, cacheFrom, to, result, moveLevel);
while (deepSearch)
{
cacheFrom = result[^1];
deepSearch = _ProcessCannotFindPath(map, cacheFrom, to, result, moveLevel);
}
}
fromData.crossLevel = oldCrossLevelFrom;
map.SetRuntimeBlockProperty(from, fromData);
if (canReach)
{
// 再设置回去
toData.crossLevel = oldCrossLevelTo;
map.SetRuntimeBlockProperty(to, toData);
}
if (result.Count == 1 && !MapUtils.CanPass(moveLevel, toData))
{
// 只有一格 且下一格子不可通行,则无法到达
result.Clear();
}
if (DebugUtil.LogEnable)
{
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);
}
return result;
}
private static bool _ProcessCannotFindPath(Map map,
int from,
int to,
ICollection<int> pathList,
int moveLevel)
{
// 如果两个格子相邻,则直接返回
var distanceToNow = map.TerrainGridSystem.CellGetHexagonDistance(from, to);
if (distanceToNow <= 1)
{
return false;
}
// 无法到达
// 获得附近一圈的格子
var nearByCells = map.TerrainGridSystem.CellGetNeighboursWithinRange(from, 1, 1);
if (nearByCells == null || nearByCells.Count <= 0) return false;
// 取最近的格子
int closestCell = -1;
var selfPos = map.TGSCellIndex2WorldPosition(from);
var targetPos = map.TGSCellIndex2WorldPosition(to);
var minDistance = Vector3.Distance(selfPos, targetPos) - 0.5f;
var toData = default(RuntimeBlockProperty);
for (int i = 0; i < nearByCells.Count; i++)
{
var cellIndex = nearByCells[i];
// 不走回头路
if (pathList.Contains(cellIndex))
{
continue;
}
// 判断是否可通行
map.GetRuntimeBlockProperty(cellIndex, out toData);
if (!MapUtils.CanPass(moveLevel, toData))
{
continue;
}
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;
}
private static bool _IsFathExist(ICollection pathList)
{
return !(pathList == null || pathList.Count <= 0);
}
}
}