Пример #1
0
    public static void FindPath(IMapController map, Vector2Int from, Vector2Int to, ref List <Vector2Int> path, Predicate <Vector2Int> IsValidNavigationTile = null)
    {
        path.Clear();
        if (from == to)
        {
            path.Add(to);
            return;
        }

        Dictionary <Vector2Int, PathInfo> visitedInfo = new Dictionary <Vector2Int, PathInfo>();
        PriorityQueue <Vector2Int>        coordsQueue = new PriorityQueue <Vector2Int>();
        BoundsInt         mapBounds  = map.CellBounds;
        List <Vector2Int> validTiles = new List <Vector2Int>();

        foreach (var position in mapBounds.allPositionsWithin)
        {
            Vector2Int pos2D = (Vector2Int)position;

            if (IsValidNavigationTile == null || !IsValidNavigationTile(pos2D))
            {
                continue;
            }

            validTiles.Add(pos2D);
            visitedInfo[pos2D] = new PathInfo(pos2D);
            coordsQueue.Enqueue(pos2D, visitedInfo[pos2D].Distance);
        }
        visitedInfo[from].Distance = 0;
        coordsQueue.UpdateKey(from, visitedInfo[from].Distance);

        while (coordsQueue.Count > 0)
        {
            Vector2Int   currentCoords = coordsQueue.Dequeue();
            Vector2Int[] deltas;
            map.GetNeighbourDeltas(currentCoords, out deltas);
            PathInfo currentInfo    = visitedInfo[currentCoords];
            int      formerDistance = currentInfo.Distance;
            if (formerDistance == Int32.MaxValue)
            {
                break;
            }
            foreach (var delta in deltas)
            {
                Vector2Int neighbourCoords = currentCoords + delta;
                if (!visitedInfo.ContainsKey(neighbourCoords))
                {
                    continue;
                }

                // TODO: Other checks: Doors, etc, etc.
                PathInfo neighbourInfo = visitedInfo[neighbourCoords];
                int      distance      = formerDistance + 1;
                if (distance < neighbourInfo.Distance)
                {
                    neighbourInfo.From     = currentCoords;
                    neighbourInfo.Distance = distance;

                    int count = coordsQueue.Count;
                    if (coordsQueue.Count > 0)
                    {
                        coordsQueue.UpdateKey(neighbourCoords, distance);
                    }
                    if (count != coordsQueue.Count)
                    {
                        Debug.LogError("Whaaaat");
                    }
                }
            }
        }

        if (visitedInfo.TryGetValue(to, out var destinationInfo) && destinationInfo.Distance != Int32.MaxValue)
        {
            List <Vector2Int> rList = new List <Vector2Int>();
            rList.Add(to);
            while (destinationInfo.From.HasValue)
            {
                rList.Add(destinationInfo.From.Value);
                destinationInfo = visitedInfo[destinationInfo.From.Value];
            }

            for (int i = rList.Count - 1; i >= 0; i--)
            {
                path.Add(rList[i]);
            }
        }
        else
        {
            path.Add(from);
        }
    }