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 FindPath(Map map, int from, int to, int moveLevel) { var result = new List(); 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); 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 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); } } }