/// <summary> /// Ctor for the A* search. It requires a searchMap from the level, a world vector start and end, /// and a heuristic strategy object. /// </summary> /// <param name="seeker">The entity looking for the path</param> /// <param name="start">A vector2 to the starting location. Must be in worldspace</param> /// <param name="end">A vector2 to the ending location. Must be in worldspace</param> /// <param name="heuristic">A heurstic strategy object</param> public SearchAStar(MovingObject seeker, Vector2 start, Vector2 end, PathHeuristic heuristic) { _seeker = seeker; _start = start; _end = end; _heuristic = heuristic; }
//A* pathfinding for faults public static List<IntVector2> GetPath(IntVector2 start, IntVector2 goal, List<IntVector2> nodes) { List<PathHeuristic> openList = new List<PathHeuristic> (); List<PathHeuristic> closedList = new List<PathHeuristic> (); PathHeuristic currentTile = new PathHeuristic(start); float startFuncTime = Time.realtimeSinceStartup; do { //Get the best fault using heuristics if(openList.Count>0){ PathHeuristic lowestFTile = null; foreach(PathHeuristic tile in openList){ if(lowestFTile==null){ lowestFTile = tile; } else if(tile.score<lowestFTile.score){ lowestFTile = tile; } if(lowestFTile.tileIndex==goal){ lowestFTile = tile; break; } } currentTile = lowestFTile; } //Put the currentTile in closedList and remove from open closedList.Add(currentTile); openList.Remove(currentTile); //If the current is at the end if(currentTile.tileIndex == goal){ List<IntVector2> pathList = new List<IntVector2>(); while(currentTile.parent!=null){ //Add parent to the pathlist pathList.Add(currentTile.tileIndex); currentTile = currentTile.parent; } pathList.Add(start); pathList.Reverse(); float time = (Time.realtimeSinceStartup-startFuncTime)*100; return pathList; } //Set adjacent list up List<IntVector2> adjacentList = GetAdjacentNodes(currentTile.tileIndex, nodes); foreach(IntVector2 adjacent in adjacentList){ //If adjacent is in closed list, skip bool adjacentInClosed = false; foreach(PathHeuristic tile in closedList){ if(tile.tileIndex == adjacent){ adjacentInClosed = true; } } if(adjacentInClosed){ continue; } //If not in open list, add it bool adjacentInOpen = false; foreach(PathHeuristic tile in openList){ if(tile.tileIndex == adjacent){ adjacentInOpen = true; } } //Add to open list if(!adjacentInOpen){ PathHeuristic newTile = new PathHeuristic(adjacent, currentTile); //Score newTile.SetScore((int)(IntVector2.Distance(adjacent,goal)*10)); openList.Add(newTile); } } } while(openList.Count>0); //Unable to find a path between the start-goal return null; }
static int GetParentCount(PathHeuristic _tile) { PathHeuristic tile = _tile; int parentCount = 0; while (tile.parent!=null) { tile = tile.parent; parentCount++; } return parentCount; }
public PathHeuristic(IntVector2 _tileIndex, PathHeuristic _parent = null) { tileIndex = _tileIndex; parent = _parent; }
/// <summary> /// Search a path with custom AStar algorithm /// (Path class is used to explore the grid) /// </summary> /// <param name="_Start">Tile to start from</param> /// <param name="_End">Tile to reach</param> /// <param name="_ChronoInfos">Struct with times value to evaluate performance</param> /// <param name="_MaxSeconds">Max time allowed to search a solution. If value is negative, no time limit applied</param> /// <returns>the shortest path from start tile to end tile if it exists, null otherwise</returns> public static Path AStarCustomBasic(Tile _Start, Tile _End, out ChronoInfos _ChronoInfos, float _MaxSeconds) { StartChrono(); if (_Start == null || !_Start.IsAccessible || _End == null || !_End.IsAccessible) { _ChronoInfos = ChronoInfos.InfosNone; return(null); } List <PathHeuristic> openList = new List <PathHeuristic>(50) { new PathHeuristic(_Start, Tile.GetManhattanDistance(_Start, _End)) }; HashSet <Tile> closeHashSet = new HashSet <Tile>(); CustomComparer <PathHeuristic> phComparer = new CustomComparer <PathHeuristic>(false); while (openList.Count > 0) { if (_MaxSeconds > 0 && chrono.Elapsed.TotalSeconds > _MaxSeconds) { _ChronoInfos = StopChrono(_Start, _End, false); return(null); } PathHeuristic pathToExtend = openList.Last(); removeFromOpenChrono -= chrono.ElapsedMilliseconds; openList.RemoveAt(openList.Count - 1); removeFromOpenChrono += chrono.ElapsedMilliseconds; Tile tileToExtend = pathToExtend.LastStep; if (tileToExtend == _End) { _ChronoInfos = StopChrono(_Start, _End, true); return(pathToExtend); } if (closeHashSet.Contains(tileToExtend)) { continue; } closeHashSet.Add(tileToExtend); foreachNeighborsChrono -= chrono.ElapsedMilliseconds; for (int i = 0; i < tileToExtend.Neighbors.Count; i++) { Tile neighbor = tileToExtend.Neighbors[i]; if (!neighbor.IsAccessible) { continue; } searchInCloseListChrono -= chrono.ElapsedMilliseconds; if (closeHashSet.Contains(neighbor)) { continue; } searchInCloseListChrono += chrono.ElapsedMilliseconds; clonePathChrono -= chrono.ElapsedMilliseconds; PathHeuristic extendedPath = new PathHeuristic(pathToExtend); clonePathChrono += chrono.ElapsedMilliseconds; extendPathChrono -= chrono.ElapsedMilliseconds; extendedPath.AddStep(neighbor, Tile.GetManhattanDistance(neighbor, _End)); extendPathChrono += chrono.ElapsedMilliseconds; searchInsertionChrono -= chrono.ElapsedMilliseconds; int indexInsertion = openList.BinarySearch(extendedPath, phComparer); if (indexInsertion < 0) { indexInsertion = ~indexInsertion; } searchInsertionChrono += chrono.ElapsedMilliseconds; insertToOpenListChrono -= chrono.ElapsedMilliseconds; openList.Insert(indexInsertion, extendedPath); insertToOpenListChrono += chrono.ElapsedMilliseconds; } foreachNeighborsChrono += chrono.ElapsedMilliseconds; } _ChronoInfos = StopChrono(_Start, _End, false); return(null); }