public static List <ILink> CalculatePath(Node from, Node to, LinkMap linkMap) { // The set of nodes already evaluated. var closedSet = new List <Node>(); // The set of currently discovered nodes that are not evaluated yet. // Initially, only the start node is known. var openSet = new List <Node> { from }; // For each node, which node it can most efficiently be reached from. // If a node can be reached from many nodes, cameFrom will eventually contain the // most efficient previous step. var cameFrom = new Dictionary <Node, ILink>(); var gScore = new Dictionary <Node, float>(); gScore[from] = 0.0f; // For each node, the total cost of getting from the start node to the goal // by passing by that node. That value is partly known, partly heuristic. var fScore = new Dictionary <Node, float>(); fScore[from] = from.Position.Distance(to.Position); var current = from; while (!openSet.IsEmpty()) { // the node in openSet having the lowest fScore[] value current = openSet.MinBy(node => fScore.GetOrPut(node, float.PositiveInfinity)); if (current == to) { return(Reconstruct(cameFrom, current)); } openSet.Remove(current); closedSet.Add(current); var linkPoint = linkMap.GetLinkPoint(current); foreach (var link in linkPoint.Links) { var neighbor = link.To; if (closedSet.Contains(neighbor)) { // Ignore the neighbor which is already evaluated. continue; } var currentGScore = gScore.GetOrPut(current, float.PositiveInfinity); var neightborGScore = gScore.GetOrPut(neighbor, float.PositiveInfinity); var linkDistance = current.Distance(neighbor); // The distance from start to a neighbor var tentativeGScore = currentGScore + linkDistance; if (!openSet.Contains(neighbor)) { openSet.Add(neighbor); } else if (tentativeGScore >= neightborGScore) { // This is not a better path. continue; } // This path is the best until now. Record it! cameFrom[neighbor] = link; gScore[neighbor] = tentativeGScore; fScore[neighbor] = gScore[neighbor] + neighbor.Distance(to); } } //Failure Debug.LogWarning("Couldn't find a path from " + from + " to " + to); return(Reconstruct(cameFrom, current)); }