144 lines
4.5 KiB
C#
144 lines
4.5 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 (!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);
|
|
while (deepSearch)
|
|
{
|
|
cacheFrom = result[^1];
|
|
deepSearch = _ProcessCannotFindPath(map, cacheFrom, to, result);
|
|
}
|
|
}
|
|
|
|
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)
|
|
{
|
|
// 无法到达
|
|
// 获得附近一圈的格子
|
|
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);
|
|
for (int i = 0; i < nearByCells.Count; i++)
|
|
{
|
|
var cellIndex = nearByCells[i];
|
|
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);
|
|
}
|
|
|
|
}
|
|
}
|