public MoveState(Character character, Pathfinder.GoalEvaluator goalEvaluator, List <Tile> path, State nextState = null) : base("Move", character, nextState) { hasReachedDestination = goalEvaluator; this.path = path; DebugLog("created with path length: {0}", path.Count); }
public Path_AStar(World world, Tile tileStart, Pathfinder.GoalEvaluator isGoal, Pathfinder.PathfindingHeuristic costEstimate) { float startTime = Time.realtimeSinceStartup; // Set path to empty Queue so that there always is something to check count on path = new Queue <Tile>(); // if tileEnd is null, then we are simply scanning for the nearest objectType. // We can do this by ignoring the heuristic component of AStar, which basically // just turns this into an over-engineered Dijkstra's algo // Check to see if we have a valid tile graph if (world.tileGraph == null) { world.tileGraph = new Path_TileGraph(world); } // Check to see if we have a valid tile graph if (world.roomGraph == null) { world.roomGraph = new Path_RoomGraph(world); } // A dictionary of all valid, walkable nodes. Dictionary <Tile, Path_Node <Tile> > nodes = world.tileGraph.nodes; // Make sure our start/end tiles are in the list of nodes! if (nodes.ContainsKey(tileStart) == false) { UnityDebugger.Debugger.LogError("Path_AStar", "The starting tile isn't in the list of nodes!"); return; } Path_Node <Tile> start = nodes[tileStart]; /* * Mostly following this pseusocode: * https://en.wikipedia.org/wiki/A*_search_algorithm */ HashSet <Path_Node <Tile> > closedSet = new HashSet <Path_Node <Tile> >(); /* * List<Path_Node<Tile>> openSet = new List<Path_Node<Tile>>(); * openSet.Add( start ); */ PathfindingPriorityQueue <Path_Node <Tile> > openSet = new PathfindingPriorityQueue <Path_Node <Tile> >(); openSet.Enqueue(start, 0); Dictionary <Path_Node <Tile>, Path_Node <Tile> > came_From = new Dictionary <Path_Node <Tile>, Path_Node <Tile> >(); Dictionary <Path_Node <Tile>, float> g_score = new Dictionary <Path_Node <Tile>, float>(); g_score[start] = 0; Dictionary <Path_Node <Tile>, float> f_score = new Dictionary <Path_Node <Tile>, float>(); f_score[start] = costEstimate(start.data); while (openSet.Count > 0) { Path_Node <Tile> current = openSet.Dequeue(); // Check to see if we are there. if (isGoal(current.data)) { Duration = Time.realtimeSinceStartup - startTime; Reconstruct_path(came_From, current); return; } closedSet.Add(current); foreach (Path_Edge <Tile> edge_neighbor in current.edges) { Path_Node <Tile> neighbor = edge_neighbor.node; if (closedSet.Contains(neighbor)) { continue; // ignore this already completed neighbor } float pathfinding_cost_to_neighbor = neighbor.data.PathfindingCost * Dist_between(current, neighbor); float tentative_g_score = g_score[current] + pathfinding_cost_to_neighbor; if (openSet.Contains(neighbor) && tentative_g_score >= g_score[neighbor]) { continue; } came_From[neighbor] = current; g_score[neighbor] = tentative_g_score; f_score[neighbor] = g_score[neighbor] + costEstimate(neighbor.data); openSet.EnqueueOrUpdate(neighbor, f_score[neighbor]); } // foreach neighbour } // while // If we reached here, it means that we've burned through the entire // openSet without ever reaching a point where current == goal. // This happens when there is no path from start to goal // (so there's a wall or missing floor or something). // We don't have a failure state, maybe? It's just that the // path list will be null. Duration = Time.realtimeSinceStartup - startTime; }