Esempio n. 1
0
        /// <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);
        }