示例#1
0
        /// <summary>
        /// Attempts to trace a path from the startin point to the end point, sychronously.
        /// May fail for a number of reasons (see <see cref="PathfindingResult"/>).
        /// </summary>
        /// <param name="startX">The starting X position.</param>
        /// <param name="startY">The starting Y position.</param>
        /// <param name="endX">The target (end) X position.</param>
        /// <param name="endY">The target (end) Y position.</param>
        /// <param name="provider">The tile provider.</param>
        /// <param name="inPath">An optional path. If null, a new list is created. If not null, this list is used as the output path.</param>
        /// <param name="path">The output path array</param>
        /// <returns></returns>
        public PathfindingResult Run(int startX, int startY, int endX, int endY, ITileProvider provider, List <PNode> path)
        {
            // Null checks.
            if (provider == null)
            {
                return(PathfindingResult.ERROR_NO_TILE_PROVIDER);
            }
            if (path == null)
            {
                return(PathfindingResult.ERROR_PATH_ARRAY_NULL);
            }

            // Validate start and end points.
            if (!provider.IsTileWalkable(startX, startY))
            {
                return(PathfindingResult.ERROR_START_NOT_WALKABLE);
            }
            if (!provider.IsTileWalkable(endX, endY))
            {
                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))
            {
                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)
                {
                    return(PathfindingResult.ERROR_PATH_TOO_LONG);
                }

                var current = open.Dequeue();

                if (current.Equals(end))
                {
                    // We found the end of the path!
                    TracePath(end, path);
                    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. Currently not implemented.

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

            return(PathfindingResult.ERROR_PATH_NOT_FOUND);
        }
示例#2
0
        private List <PNode> GetNear(PNode node, ITileProvider 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);
        }