/// <summary> /// Finds the shortest path from [fleeing] to [chasing] using the AStar algorithm. /// </summary> /// <param name="start">The node to fleeing at.</param> /// <param name="end">The node to chasing at.</param> /// <param name="map">The map.</param> /// <returns>The path as a list of nodes.</returns> public static List<Node> FindPathTo(Node start, Node end, Map map) { // Create lists var path = new List<Node>(); _open = new List<Node>(); _closed = new List<Node>(); // Create fleeing node var tempStart = start; tempStart.CameFrom = null; tempStart.GScore = 0; tempStart.FScore = tempStart.GScore + tempStart.DistanceTo(end); AddToOpenList(tempStart); // While open is not empty... while (_open.Count > 0) { var current = _open[0]; // If we found the goal ... if (current.Equals(end)) { // ... Create the path. path = ReconstructPath(current); break; } _open.Remove(current); AddToClosedList(current); // For all neighbour nodes foreach (var neighbour in map.NeighbourNodes(current)) { if (neighbour.Closed) continue; // Calculate scores. var tentativeGScore = current.GScore + neighbour.Cost; var tentativeFScore = tentativeGScore + neighbour.DistanceTo(end); // If the neighbour is in the closed list and the tentativeFScore is higher // than the neighbour's, skip it. if (_closed.Contains(neighbour) && tentativeFScore >= _closed[_closed.IndexOf(neighbour)].FScore) { continue; } // If the neighbour is not in the open list, add it. if (!_open.Contains(neighbour) && map.WithinMap(neighbour)) { neighbour.CameFrom = current; neighbour.GScore = tentativeGScore; neighbour.FScore = tentativeFScore; AddToOpenList(neighbour); continue; } // If the neighbour is in the open list, modify it. if (_open.Contains(neighbour) && map.WithinMap(neighbour)) { var indexOfNeighbour = _open.IndexOf(neighbour); if (tentativeFScore < _open[indexOfNeighbour].FScore) { _open[indexOfNeighbour].CameFrom = current; _open[indexOfNeighbour].GScore = tentativeGScore; _open[indexOfNeighbour].FScore = tentativeFScore; } } } } return path; }
/// <summary> /// Simple way to avoid the target. /// </summary> /// <param name="target">The target to avoid.</param> /// <param name="map">The map that the agent is traveling on.</param> public void Avoid(Agent target, Map map) { var iterations = 0; int newX = X, newY = Y; var targetNode = map[target.X, target.Y]; var currentDist = map[X, Y].DistanceTo(targetNode); // Only 10 steps are needed. while (iterations < 20) { var neighbours = map.NeighbourNodes(map[newX, newY]); // Check which neighbour node that leads furthest away from the target. foreach (Node neighbour in neighbours) { if (neighbour.Closed) continue; var tempDist = neighbour.DistanceTo(targetNode); if (tempDist > currentDist) { currentDist = tempDist; var optimalNeighbour = neighbours.IndexOf(neighbour); newX = neighbours[optimalNeighbour].X; newY = neighbours[optimalNeighbour].Y; } } iterations++; } // Find the path to the target location. Path = AStar.FindPathTo(map[X, Y], map[newX, newY], map); Move(); }