using System.Collections; using System.Collections.Generic; using System.Text; using Gameplay.Area; using Gameplay.Character; using Gameplay.Level; using Gameplay.PostProcess.BlackArea; using Gameplay.Unit; using UnityEngine; using static Gameplay.Map; namespace Gameplay { public static class PathFinder { private static List _cacheChangedCellIndexs = new List(); 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]; if (unit == moveUnit) { // 自己所在格子不需要设置 continue; } if (unit.statusData.isOnVehicle) { // 在载具上的单位不需要设置 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); } } if (moveUnit.commonData.troopId == ETroopsId.Self) { // 如果是己方,需要将所有未照亮的格子设置为不可通行 var allLightPoints = BlackAreaManager.instance.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); } } } 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) { var map = LevelManager.Instance.CurrentLevel.Map; var crossLevel = moveUnit.commonData.crossLevel; map.GetRuntimeBlockProperty(cellIndex, out var runtimeBlockProperty); if (runtimeBlockProperty.isEmptyBlock) return false; if (crossLevel <= runtimeBlockProperty.crossLevel) return false; // 额外判断当前格子是否有单位 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; } 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); if (runtimeBlockProperty.isEmptyBlock) return false; if (crossLevel <= runtimeBlockProperty.crossLevel) return false; return true; } public static List FindPath(Map map, int to, GameUnit moveUnit) { var moveLevel = moveUnit.commonData.crossLevel; var from = moveUnit.transData.cellIndex; var result = new List(); if (from == to) { // 同一个格子 result.Add(to); return result; } var canReach = true; var mapData = map.GetBlockData(to); if (mapData == null) { DebugUtil.LogError("FindPath: mapData is null, to: " + to); return result; } if (!_CheckEndCanPass(to, moveUnit)) { // 如果终点不可通行,直接走无法走通的逻辑 // 地形层面的不可通行 canReach = false; } _RuntimeMarkMapCrossState(moveUnit); var toData = default(RuntimeBlockProperty); if (canReach) { map.GetRuntimeBlockProperty(to, out toData); MapUtils.ForceSetCanCross(true, ref toData); map.SetRuntimeBlockProperty(to, toData); _cacheChangedCellIndexs.Add(to); result = map.TerrainGridSystem.FindPath(from, to, moveLevel); } // 无法直接走通 if (!_IsPathExist(result)) { var cacheFrom = from; var deepSearch = _ProcessCannotFindPath(map, cacheFrom, to, result, moveLevel); while (deepSearch) { cacheFrom = result[^1]; deepSearch = _ProcessCannotFindPath(map, cacheFrom, to, result, moveLevel); } } if (result.Count == 1 && !CanPass(to, moveUnit)) { // 只有一格 且下一格子不可通行,则无法到达 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); } _RuntimeRecoverMapCrossState(); return result; } private static bool _ProcessCannotFindPath(Map map, int from, int to, ICollection 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; for (int i = 0; i < nearByCells.Count; i++) { var cellIndex = nearByCells[i]; // 不走回头路 if (pathList.Contains(cellIndex)) { continue; } // 判断是否可通行 map.GetRuntimeBlockProperty(cellIndex, out var 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 _IsPathExist(ICollection pathList) { return !(pathList == null || pathList.Count <= 0); } } }