Ejemplo n.º 1
0
    public PathfindingResult Run(int startX, int startY, int endX, int endY, TileProvider provider, out List <PNode> path)
    {
        if (provider == null)
        {
            path = null;
            return(PathfindingResult.ERROR_INTERNAL);
        }

        // Validate start and end points.
        if (!provider.TileInBounds(startX, startY))
        {
            path = null;
            return(PathfindingResult.ERROR_START_OUT_OF_BOUNDS);
        }
        if (!provider.TileInBounds(endX, endY))
        {
            path = null;
            return(PathfindingResult.ERROR_END_OUT_OF_BOUNDS);
        }
        if (!provider.IsTileWalkable(startX, startY))
        {
            path = null;
            return(PathfindingResult.ERROR_START_NOT_WALKABLE);
        }
        if (!provider.IsTileWalkable(endX, endY))
        {
            path = null;
            return(PathfindingResult.ERROR_END_NOT_WALKABLE);
        }

        // Clear everything up.
        Clear();

        var start = PNode.Create(startX, startY);
        var end   = PNode.Create(endX, endY);

        // Check the start/end relationship.
        if (start.Equals(end))
        {
            path = null;
            return(PathfindingResult.ERROR_START_IS_END);
        }

        // Add the starting point to all relevant structures.
        open.Enqueue(start, 0f);
        cameFrom[start]  = start;
        costSoFar[start] = 0f;

        int count;

        while ((count = open.Count) > 0)
        {
            // Detect if the current open amount exceeds the capacity.
            // This only happens in very large open areas. Corridors and hallways will never cause this, not matter how large the actual path length.
            if (count >= MAX - 8)
            {
                path = null;
                return(PathfindingResult.ERROR_PATH_TOO_LONG);
            }

            var current = open.Dequeue();

            if (current.Equals(end))
            {
                // We found the end of the path!
                path = TracePath(end);
                return(PathfindingResult.SUCCESSFUL);
            }

            // Get all neighbours (tiles that can be walked on to)
            var neighbours = GetNear(current, provider);
            foreach (PNode n in neighbours)
            {
                float newCost = costSoFar[current] + GetCost(current, n); // Note that this could change depending on speed changes per-tile.

                if (!costSoFar.ContainsKey(n) || newCost < costSoFar[n])
                {
                    costSoFar[n] = newCost;
                    float priority = newCost + Heuristic(current, n);
                    open.Enqueue(n, priority);
                    cameFrom[n] = current;
                }
            }
        }

        path = null;
        return(PathfindingResult.ERROR_INTERNAL);
    }
Ejemplo n.º 2
0
    private List <PNode> GetNear(PNode node, TileProvider provider)
    {
        // Want to add nodes connected to the center node, if they are walkable.
        // This code stops the pathfinder from cutting corners, and going through walls that are diagonal from each other.

        near.Clear();

        // Left
        left = false;
        if (provider.IsTileWalkable(node.X - 1, node.Y))
        {
            near.Add(PNode.Create(node.X - 1, node.Y));
            left = true;
        }

        // Right
        right = false;
        if (provider.IsTileWalkable(node.X + 1, node.Y))
        {
            near.Add(PNode.Create(node.X + 1, node.Y));
            right = true;
        }

        // Above
        above = false;
        if (provider.IsTileWalkable(node.X, node.Y + 1))
        {
            near.Add(PNode.Create(node.X, node.Y + 1));
            above = true;
        }

        // Below
        below = false;
        if (provider.IsTileWalkable(node.X, node.Y - 1))
        {
            near.Add(PNode.Create(node.X, node.Y - 1));
            below = true;
        }

        // Above-Left
        if (left && above)
        {
            if (provider.IsTileWalkable(node.X - 1, node.Y + 1))
            {
                near.Add(PNode.Create(node.X - 1, node.Y + 1));
            }
        }

        // Above-Right
        if (right && above)
        {
            if (provider.IsTileWalkable(node.X + 1, node.Y + 1))
            {
                near.Add(PNode.Create(node.X + 1, node.Y + 1));
            }
        }

        // Below-Left
        if (left && below)
        {
            if (provider.IsTileWalkable(node.X - 1, node.Y - 1))
            {
                near.Add(PNode.Create(node.X - 1, node.Y - 1));
            }
        }

        // Below-Right
        if (right && below)
        {
            if (provider.IsTileWalkable(node.X + 1, node.Y - 1))
            {
                near.Add(PNode.Create(node.X + 1, node.Y - 1));
            }
        }

        return(near);
    }