/// <summary> /// Computes the Manhattan distance from the current node to the end node. /// </summary> /// <param name="current">The current node.</param> /// <param name="end">The end node.</param> /// <returns>Returns the Manhattan distance from the current node to the end node.</returns> private static int Heuristic(AStarNode current, AStarNode end) { return(Math.Abs(current.X - end.X) + Math.Abs(current.Y - current.Y)); }
public AStarNode GetNodeNearestWaterSource(AStarNode node) { List <AStarNode> list = new List <AStarNode>(); for (int i = 1; i < 30; i++) { AStarNode goalNode = this.GetNode(node.X + i, node.Y); if (goalNode is not null && goalNode.TileClear && !goalNode.IsWateringCanFillingSource()) { list.Add(goalNode); } goalNode = this.GetNode(node.X - i, node.Y); if (goalNode is not null && goalNode.TileClear && !goalNode.IsWateringCanFillingSource()) { list.Add(goalNode); } goalNode = this.GetNode(node.X, node.Y + i); if (goalNode is not null && goalNode.TileClear && !goalNode.IsWateringCanFillingSource()) { list.Add(goalNode); } goalNode = this.GetNode(node.X, node.Y - i); if (goalNode is not null && goalNode.TileClear && !goalNode.IsWateringCanFillingSource()) { list.Add(goalNode); } if (list.Count > 0) { break; } } if (list.Count == 0) { return(null); } int minIndex = 0; float minDistance = float.MaxValue; for (int i = 1; i < list.Count; i++) { float distance = Vector2.Distance(ClickToMoveHelper.PlayerOffsetPosition, list[i].NodeCenterOnMap); if (distance < minDistance) { minDistance = distance; minIndex = i; } } int x = node.X; int y = node.Y; if (list[minIndex].X != node.X) { x = list[minIndex].X <= node.X ? list[minIndex].X + 1 : list[minIndex].X - 1; } else { y = list[minIndex].Y <= node.Y ? list[minIndex].Y + 1 : list[minIndex].Y - 1; } return(this.GetNode(x, y)); }
public AStarPath FindPathToNeighbourDiagonalWithBubbleCheck(AStarNode startNode, AStarNode endNode) { AStarPath pathWithBubbleCheck = this.FindPathWithBubbleCheck(startNode, endNode); if (pathWithBubbleCheck is not null) { return(pathWithBubbleCheck); } if (endNode.FakeTileClear) { double minDistance = double.MaxValue; AStarNode nearestNode = null; foreach (WalkDirection walkDirection in WalkDirection.DiagonalDirections) { AStarNode node = this.GetNode(endNode.X + walkDirection.X, endNode.Y + walkDirection.Y); if (node is not null && node.TileClear) { double distance = ClickToMoveHelper.SquaredEuclideanDistance( startNode.X, startNode.Y, node.X, node.Y); if (distance < minDistance) { nearestNode = node; minDistance = distance; } } } if (nearestNode is not null) { return(this.FindPathWithBubbleCheck(startNode, nearestNode)); } } return(null); }
public AStarNode GetNearestLandNodePerpendicularToWaterSource(AStarNode nodeClicked) { AStarNode result = nodeClicked; AStarNode node; if (this.FarmerNodeOffset.X == nodeClicked.X || (this.FarmerNodeOffset.Y != nodeClicked.Y && Math.Abs(nodeClicked.X - this.FarmerNodeOffset.X) > Math.Abs(nodeClicked.Y - this.FarmerNodeOffset.Y))) { if (nodeClicked.Y > this.FarmerNodeOffset.Y) { for (int i = nodeClicked.Y; i >= this.FarmerNodeOffset.Y; i--) { node = this.GetNode(nodeClicked.X, i); if (node is not null && node.TileClear && !node.IsWateringCanFillingSource()) { return(result); } result = node; } } else { for (int i = nodeClicked.Y; i <= this.FarmerNodeOffset.Y; i++) { node = this.GetNode(nodeClicked.X, i); if (node is not null && node.TileClear && !node.IsWateringCanFillingSource()) { return(result); } result = node; } } } else if (nodeClicked.X > this.FarmerNodeOffset.X) { for (int i = nodeClicked.X; i >= this.FarmerNodeOffset.X; i--) { node = this.GetNode(i, nodeClicked.Y); if (node is not null && node.TileClear && !node.IsWateringCanFillingSource()) { return(result); } result = node; } } else { for (int i = nodeClicked.X; i <= this.FarmerNodeOffset.X; i++) { node = this.GetNode(i, nodeClicked.Y); if (node is not null && node.TileClear && !node.IsWateringCanFillingSource()) { return(result); } result = node; } } node = this.GetNodeNearestWaterSource(nodeClicked) ?? this.GetNodeNearestWaterSource(this.FarmerNodeOffset); return(node); }
/// <summary> /// Computes a path between the two specified nodes. /// </summary> /// <param name="startNode">The start node.</param> /// <param name="endNode">The end node.</param> /// <returns>A path from the start node to the end node.</returns> public AStarPath FindPath(AStarNode startNode, AStarNode endNode) { if (startNode is null || endNode is null) { return(null); } startNode.GCost = 0; startNode.HCost = AStarGraph.Heuristic(startNode, endNode); startNode.PreviousNode = null; // The set of discovered nodes that may need to be expanded. // Initially, only the start node is known. FastBinaryHeap <AStarNode> openSet = new FastBinaryHeap <AStarNode>(); openSet.Push(startNode); // The set of nodes already expanded. HashSet <AStarNode> closedSet = new HashSet <AStarNode>(); while (!openSet.IsEmpty()) { AStarNode currentNode = openSet.Pop(); if (currentNode == endNode) { return(new AStarPath(startNode, endNode)); } closedSet.Add(currentNode); foreach (AStarNode neighbour in currentNode.GetNeighbours()) { if (closedSet.Contains(neighbour) || (this.gameLocation is FarmHouse && !endNode.IsBlockingBedTile() && neighbour.IsBlockingBedTile())) { continue; } int gCost = currentNode.GCost + 1; bool visited = openSet.Contains(neighbour); if (gCost < neighbour.GCost || !visited) { // This path to neighbour is better than any previous one. Record it! neighbour.GCost = gCost; neighbour.HCost = AStarGraph.Heuristic(neighbour, endNode); neighbour.PreviousNode = currentNode; if (visited) { openSet.Heapify(neighbour); } else { openSet.Push(neighbour); } } } } // Open set is empty but goal was never reached. return(null); }