/// <summary> /// Get all the neighbors of a given tile in the grid. /// </summary> /// <param name="_node">Node to get neighbors for.</param> /// <returns>List of node neighbors.</returns> public List <Node> GetNeighbours(Node _node, ePathFindDistanceType _distanceType) { if (m_Neighbours.Count > 0) { m_Neighbours.Clear(); m_Neighbours = null; } m_Neighbours = new List <Node>(); int x = 0, y = 0; switch (_distanceType) { case ePathFindDistanceType.Manhattan: y = 0; for (x = -1; x <= 1; ++x) { Vector3Int position = new Vector3Int(x, y, 0); AddNodeNeighbour(position, _node); } x = 0; for (y = -1; y <= 1; ++y) { Vector3Int position = new Vector3Int(x, y, 0); AddNodeNeighbour(position, _node); } break; case ePathFindDistanceType.Euclidean: for (x = -1; x <= 1; x++) { for (y = -1; y <= 1; y++) { Vector3Int position = new Vector3Int(x, y, 0); AddNodeNeighbour(position, _node); } } break; default: break; } return(m_Neighbours); }
/// <summary> /// Find a path between two points. /// </summary> /// <param name="_grid">Grid to search.</param> /// <param name="_startPos">Starting position.</param> /// <param name="_targetPos">Ending position.</param> /// <param name="_distance">The type of distance, Euclidean or Manhattan.</param> /// <param name="_ignorePrices">If true, will ignore tile price (how much it "cost" to walk on).</param> /// <returns>List of points that represent the path to walk.</returns> public static HashSet <Vector3Int> FindPath( Grid _grid, Vector3Int _startPos, Vector3Int _targetPos, ePathFindDistanceType _distance = ePathFindDistanceType.Euclidean, bool _ignorePrices = false) { // find path List <Node> nodes_path = _ImpFindPath(_grid, _startPos, _targetPos, _distance, _ignorePrices); // convert to a list of points and return HashSet <Vector3Int> ret = new HashSet <Vector3Int>(); if (nodes_path != null) { foreach (Node node in nodes_path) { ret.Add(node.m_GridPosition); } } return(ret); }
/// <summary> /// Internal function that implements the path-finding algorithm. /// </summary> /// <param name="_grid">Grid to search.</param> /// <param name="_startPos">Starting position.</param> /// <param name="_targetPos">Ending position.</param> /// <param name="_distance">The type of distance, Euclidean or Manhattan.</param> /// <param name="_ignorePrices">If true, will ignore tile price (how much it "cost" to walk on).</param> /// <returns>List of grid nodes that represent the path to walk.</returns> private static List <Node> _ImpFindPath(Grid _grid, Vector3Int _startPos, Vector3Int _targetPos, ePathFindDistanceType _distance = ePathFindDistanceType.Euclidean, bool _ignorePrices = false) { Node startNode = _grid.m_NodesDic[_startPos]; Node targetNode = _grid.m_NodesDic[_targetPos]; List <Node> openSet = new List <Node>(); HashSet <Node> closedSet = new HashSet <Node>(); openSet.Add(startNode); while (openSet.Count > 0) { Node currentNode = openSet[0]; //Debug.Log( "[currentNode] x = " + currentNode.gridX + " y = " + currentNode.gridY ); for (int i = 1; i < openSet.Count; i++) { if (openSet[i].fCost < currentNode.fCost || openSet[i].fCost == currentNode.fCost && openSet[i].m_hCost < currentNode.m_hCost) { currentNode = openSet[i]; } } openSet.Remove(currentNode); closedSet.Add(currentNode); if (currentNode.m_GridPosition == targetNode.m_GridPosition) { return(RetracePath(startNode, targetNode)); } foreach (Node neighbour in _grid.GetNeighbours(currentNode, _distance)) { if (!neighbour.m_Walkable || closedSet.Contains(neighbour)) { continue; } int newMovementCostToNeighbour = currentNode.m_gCost + GetDistance(currentNode, neighbour) * (_ignorePrices ? 1 : (int)(10.0f * neighbour.m_Price)); if (newMovementCostToNeighbour < neighbour.m_gCost || !openSet.Contains(neighbour)) { neighbour.m_gCost = newMovementCostToNeighbour; neighbour.m_hCost = GetDistance(neighbour, targetNode); neighbour.m_Parent = currentNode; if (!openSet.Contains(neighbour)) { openSet.Add(neighbour); } } } } Debug.LogError("end of _ImpFindPath() return null"); return(null); }