Пример #1
0
        private float GetCost(PNode a, PNode b)
        {
            // Only intended for neighbours.

            // Is directly horzontal
            if (Math.Abs(a.X - b.X) == 1 && a.Y == b.Y)
            {
                return(1);
            }

            // Directly vertical.
            if (Math.Abs(a.Y - b.Y) == 1 && a.X == b.X)
            {
                return(1);
            }

            // Assume that it is on one of the corners.
            return(DIAGONAL_DST);
        }
Пример #2
0
        private List <PNode> TracePath(PNode end)
        {
            List <PNode> path  = new List <PNode>();
            PNode        child = end;

            bool run = true;

            while (run)
            {
                PNode previous = cameFrom[child];
                path.Add(child);
                if (previous != null && child != previous)
                {
                    child = previous;
                }
                else
                {
                    run = false;
                }
            }

            path.Reverse();
            return(path);
        }
Пример #3
0
        public PathfindingResult Run(int startX, int startY, int endX, int endY, Map map, out List <PNode> path)
        {
            if (map == null)
            {
                path = null;
                return(PathfindingResult.ERROR_INTERNAL);
            }
            if (!map.Initialized)
            {
                path = null;
                return(PathfindingResult.ERROR_INTERNAL);
            }

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

            // Clear everything up.
            Clear();

            var start = new PNode(startX, startY);
            var end   = new PNode(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;

                    // Clear everything up.
                    Clear();

                    return(PathfindingResult.ERROR_PATH_TOO_LONG);
                }

                var current = open.Dequeue();

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

                    // Clear everything up.
                    Clear();

                    return(PathfindingResult.SUCCESSFUL);
                }

                // Get all neighbours (tiles that can be walked on to)
                var neighbours = GetNear(current, map);
                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;
                    }
                }
            }

            // Clear everything up.
            Clear();

            path = null;
            return(PathfindingResult.ERROR_INTERNAL);
        }
Пример #4
0
        private List <PNode> GetNear(PNode node, Map map)
        {
            // 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 (map.Interaction.IsTileWalkable(node.X - 1, node.Y))
            {
                near.Add(new PNode(node.X - 1, node.Y));
                left = true;
            }

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

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

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

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

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

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

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

            return(near);
        }
Пример #5
0
 private float Heuristic(PNode a, PNode b)
 {
     // Gives a rough distance.
     return(Math.Abs(a.X - b.X) + Math.Abs(a.Y - b.Y));
 }