/// <summary> /// Generates a path on the given map /// </summary> /// <param name="diagonal"></param> /// <returns></returns> public List<Point> GeneratePath(bool diagonal = true) { // Check for whether it's even possible first, and then return early if it's not var adjPoint = GetAdjacentCell(_end.Position.X, _end.Position.Y); if(adjPoint == new Point(-1, -1)) return new List<Point>(); // Otherwise, begin the A* search // Start at the beginning _openList.Add(_start); _current = _start; // Let us find where we need to go while (true) { // If we're out of places to go.. if (_openList.Count == 0) break; _current = GetSmallestF(); if (_current.Position == _end.Position) break; _openList.Remove(_current); _closedList.Add(_current.Position); if (diagonal) { AddAdjacentCellToNodeToOpenList(_current, 1, -1, 14); AddAdjacentCellToNodeToOpenList(_current, -1, -1, 14); AddAdjacentCellToNodeToOpenList(_current, -1, 1, 14); AddAdjacentCellToNodeToOpenList(_current, 1, 1, 14); } AddAdjacentCellToNodeToOpenList(_current, 0, -1, 10); AddAdjacentCellToNodeToOpenList(_current, -1, 0, 10); AddAdjacentCellToNodeToOpenList(_current, 1, 0, 10); AddAdjacentCellToNodeToOpenList(_current, 0, 1, 10); } while (_current != null) { bool endOnClosed = false; for (int v = 0; v < _openList.Count; v++) if (_openList[v].Position == _end.Position) endOnClosed = true; if (endOnClosed) _waypoints.Add(_current.Position); // Walk _current = _current.Parent; } _waypoints.Reverse(); return _waypoints; }
public AStarSearcher(TmxMap map, Point dest, Point start) { _map = map; // Setup our start and goal here _start = new GraphNode(start, null); _end = new GraphNode(dest, null); }
public GraphNode(Point position, GraphNode parent) { Position = position; Parent = parent; }
private void AddAdjacentCellToNodeToOpenList(GraphNode parentNode, int xOffset, int yOffset, int gCost) { // Get adjacent cell var adjacentCell = GetAdjacentCell(parentNode.Position.X + xOffset, parentNode.Position.Y + yOffset); // Ignore blocked and invalid points if (adjacentCell == new Point(-1, -1)) return; /** * * 1) A* requires searching the entire god damn map sometimes; runs on the same thread; will search every node to find a path just to find out that it's not traversable 2) If the path-finding leads to somewhere that is ultimately not reachable, the code will stutter horribly and die. Optimizations: 1) Make sure we don't bother path finding to a place that is unreachable 2) Remove linearity from closedList; replace it with something more high speed (O(1), hash set?) * * #2 was implemented here, gains are huge as is vs. a linear search * * */ // Ignore stuff on the closed list; hash set for performance reasons if (_closedList.Contains(adjacentCell)) return; var adjacentNode = _openList.SingleOrDefault(n => n.Position == adjacentCell); if (adjacentNode != null) { if (parentNode.G + gCost < adjacentNode.G) { adjacentNode.Parent = parentNode; adjacentNode.G = parentNode.G + gCost; adjacentNode.F = adjacentNode.G + adjacentNode.H; } return; } // Otherwise, set some parameters for ourselves var dist = GetDistance(adjacentCell, _end.Position); var newNode = new GraphNode(adjacentCell, parentNode) { G = gCost, H = dist }; newNode.F = newNode.G + newNode.H; _openList.Add(newNode); }