using System.Collections.Generic; using UnityEngine; namespace Utils { public static class Pathfinder { public static List FindPath(Entity.Entity entity, Vector2 target, float maxDistance) { Vector2 start = entity.Position; // 计算起点和终点所在的瓦片坐标 var startTile = GetTileCoord(start); var endTile = GetTileCoord(target); // 如果超出最大距离,直接返回直线路径或空路径 if (Vector2.Distance(start, target) > maxDistance) { return new List { start, target }; } // A*算法数据结构 var cameFrom = new Dictionary(); var gScore = new Dictionary(); var fScore = new Dictionary(); var openSet = new List(); // 初始化 gScore[startTile] = 0; fScore[startTile] = Heuristic(startTile, endTile); openSet.Add(startTile); var closestNode = startTile; var closestDist = Vector2.Distance(start, target); while (openSet.Count > 0) { // 获取fScore最小的节点 var current = openSet[0]; foreach (var node in openSet) { if (fScore.GetValueOrDefault(node, float.MaxValue) < fScore.GetValueOrDefault(current, float.MaxValue)) { current = node; } } // 检查是否到达目标 if (current == endTile) { return ReconstructPath(cameFrom, current, start, target); } openSet.Remove(current); // 检查最大距离限制 var currentDist = Vector2.Distance( new Vector2(current.x, current.y), target); if (currentDist < closestDist) { closestDist = currentDist; closestNode = current; } if (gScore[current] > maxDistance) { return ReconstructPath(cameFrom, closestNode, start, target); } // 遍历邻居(8方向) for (var dx = -1; dx <= 1; dx++) { for (var dy = -1; dy <= 1; dy++) { if (dx == 0 && dy == 0) continue; var neighbor = new Vector2Int(current.x + dx, current.y + dy); // 跳过不可通行区域 if (!Map.MapGenerator.Instance.CanPassThrough(neighbor.x, neighbor.y)) { continue; } // 计算移动成本 var moveCost = GetMovementCost(current, neighbor); var tentativeGScore = gScore[current] + moveCost; // 跳过超出最大距离的路径 if (tentativeGScore > maxDistance) { continue; } // 发现新节点或找到更好路径 if (tentativeGScore < gScore.GetValueOrDefault(neighbor, float.MaxValue)) { cameFrom[neighbor] = current; gScore[neighbor] = tentativeGScore; fScore[neighbor] = tentativeGScore + Heuristic(neighbor, endTile); if (!openSet.Contains(neighbor)) { openSet.Add(neighbor); } } } } } // 无法找到完整路径时返回局部最优解 return ReconstructPath(cameFrom, closestNode, start, target); } // 获取瓦片坐标(每个瓦片覆盖±0.5范围) private static Vector2Int GetTileCoord(Vector2 position) { return new Vector2Int( Mathf.RoundToInt(position.x), Mathf.RoundToInt(position.y) ); } // 计算启发式估值(欧几里得距离) private static float Heuristic(Vector2Int a, Vector2Int b) { return Vector2.Distance( new Vector2(a.x, a.y), new Vector2(b.x, b.y) ); } // 获取移动成本 private static float GetMovementCost(Vector2Int from, Vector2Int to) { // 计算基础距离(正交=1,对角=√2) var distance = (from.x == to.x || from.y == to.y) ? 1f : 1.4142f; // 应用目标瓦片的速度削减率 var costModifier = Map.MapGenerator.Instance.GetTileCost(to.x, to.y); // 成本 = 距离 × (1 + 速度削减率) return distance * (1 + costModifier); } // 重建路径 private static List ReconstructPath( Dictionary cameFrom, Vector2Int current, Vector2 start, Vector2 end) { // 构建瓦片路径 var tilePath = new List(); tilePath.Add(current); while (cameFrom.ContainsKey(current)) { current = cameFrom[current]; tilePath.Add(current); } tilePath.Reverse(); // 转换为实际坐标路径 var path = new List(); path.Add(start); // 添加精确起点 // 添加路径点(瓦片中心) foreach (var tile in tilePath) { path.Add(new Vector2(tile.x, tile.y)); } path.Add(end); // 添加精确终点 return path; } } }