Пример #1
0
        /// <summary>
        /// Calculates the neighbors of a specific point based on the DestinationMode property of <paramref name="userData"/>.
        /// </summary>
        /// <param name="endPosition">The destination point.</param>
        /// <param name="userData">The data provided by the user.</param>
        /// <returns>Null if the DestinationMode property of <paramref name="userData"/> is <see cref="DestinationModeFlags.Exact"/>, otherwise an array of neighbor points.</returns>
        /// <exception cref="ArgumentOutOfRangeException">If userData.DestinationMode is not a valid <see cref="DestinationModeFlags"/> value.</exception>
        private static Point[] GetDestinationPoints(Point endPosition, FindPathData userData)
        {
            if (userData.DestinationModeFlags == DestinationModeFlags.Exact)
            {
                return(null);
            }

            var output = new List <Point>(8);

            if (userData.DestinationModeFlags.HasFlag(DestinationModeFlags.CardinalNeighbor))
            {
                output.Add(new Point(endPosition.X - 1, endPosition.Y));
                output.Add(new Point(endPosition.X, endPosition.Y - 1));
                output.Add(new Point(endPosition.X + 1, endPosition.Y));
                output.Add(new Point(endPosition.X, endPosition.Y + 1));
            }

            if (userData.DestinationModeFlags.HasFlag(DestinationModeFlags.IntercardinalNeighbor))
            {
                output.Add(new Point(endPosition.X - 1, endPosition.Y - 1));
                output.Add(new Point(endPosition.X + 1, endPosition.Y - 1));
                output.Add(new Point(endPosition.X + 1, endPosition.Y + 1));
                output.Add(new Point(endPosition.X - 1, endPosition.Y + 1));
            }

            return(output.Count == 0 ? null : output.ToArray());
        }
Пример #2
0
        /// <summary>
        ///     Finds the path.
        /// </summary>
        /// <param name="startPosition">The start position.</param>
        /// <param name="endPosition">The end position.</param>
        /// <param name="depth">An output variable; the depth of the path.</param>
        /// <param name="userData">The user data used when processing nodes.</param>
        /// <returns>A list of points defining the found path.</returns>
        public Point[] FindPath(Point startPosition, Point endPosition, out int depth, FindPathData userData)
        {
            userData.StartPosition = startPosition;
            userData.EndPosition   = endPosition;
            var closedNodes   = new List <PathTreeNode>();
            var possibleNodes = new List <PathTreeNode>();
            var openNodes     = new List <PathTreeNode>
            {
                new PathTreeNode(startPosition, null, 0)
            };

            var destinationPoints = GetDestinationPoints(endPosition, userData);

            while (true)
            {
                if (openNodes.Count == 0)
                {
                    if (possibleNodes.Any())
                    {
                        return(CreatePath(possibleNodes.First(), out depth, userData));
                    }

                    depth = 0;
                    return(Array.Empty <Point>());
                }

                openNodes.Sort((node1, node2) => node1.Weight.CompareTo(node2.Weight));

                var currentNode     = openNodes[0];
                var currentPosition = currentNode.Position;
                if (!closedNodes.Contains(currentNode))
                {
                    if (userData.DestinationModeFlags.HasFlag(DestinationModeFlags.Exact) && currentPosition == endPosition)
                    {
                        return(CreatePath(currentNode, out depth, userData));
                    }

                    if (destinationPoints != null && destinationPoints.Any(x => x == currentPosition))
                    {
                        if (!userData.DestinationModeFlags.HasFlag(DestinationModeFlags.Exact))
                        {
                            return(CreatePath(currentNode, out depth, userData));
                        }
                        possibleNodes.Add(currentNode);
                    }

                    var left  = ProcessNode(currentNode, -1, 0, openNodes, closedNodes, endPosition, userData);
                    var up    = ProcessNode(currentNode, 0, -1, openNodes, closedNodes, endPosition, userData);
                    var right = ProcessNode(currentNode, 1, 0, openNodes, closedNodes, endPosition, userData);
                    var down  = ProcessNode(currentNode, 0, 1, openNodes, closedNodes, endPosition, userData);

                    if (left != null && up != null)
                    {
                        ProcessNode(currentNode, -1, -1, openNodes, closedNodes, endPosition, userData);
                    }

                    if (right != null && up != null)
                    {
                        ProcessNode(currentNode, 1, -1, openNodes, closedNodes, endPosition, userData);
                    }

                    if (right != null && down != null)
                    {
                        ProcessNode(currentNode, 1, 1, openNodes, closedNodes, endPosition, userData);
                    }

                    if (left != null && down != null)
                    {
                        ProcessNode(currentNode, -1, 1, openNodes, closedNodes, endPosition, userData);
                    }

                    closedNodes.Add(currentNode);
                }

                openNodes.RemoveAt(0);
            }
        }
Пример #3
0
 /// <summary>
 ///     Finds the path.
 /// </summary>
 /// <param name="startColumn">The start column.</param>
 /// <param name="startRow">The start row.</param>
 /// <param name="endColumn">The end column.</param>
 /// <param name="endRow">The end row.</param>
 /// <param name="depth">An output variable; the depth of the path.</param>
 /// <param name="userData">The user data used when processing nodes.</param>
 /// <returns>A list of points defining the found path.</returns>
 public Point[] FindPath(int startColumn, int startRow, int endColumn, int endRow, out int depth, FindPathData userData) => FindPath(new Point(startColumn, startRow), new Point(endColumn, endRow), out depth, userData);
Пример #4
0
        /// <summary>
        ///     Processes the node.
        /// </summary>
        /// <param name="currentNode">The current node.</param>
        /// <param name="columnOffset">The column offset.</param>
        /// <param name="rowOffset">The row offset.</param>
        /// <param name="openNodes">The list of open nodes that will be added to as nodes are processed.</param>
        /// <param name="closedNodes">The closed nodes.</param>
        /// <param name="endPosition">The end position.</param>
        /// <param name="userData">The user data.</param>
        /// <returns>A new node positioned next to the current node based on columnOffset and rowOffset.</returns>
        private PathTreeNode ProcessNode(PathTreeNode currentNode, int columnOffset, int rowOffset, ICollection <PathTreeNode> openNodes, IEnumerable <PathTreeNode> closedNodes, Point endPosition, FindPathData userData)
        {
            var position = new Point(currentNode.Position.X + columnOffset, currentNode.Position.Y + rowOffset);
            var weight   = currentNode.Weight + userData?.GetWeight(position, endPosition) ?? 0;
            var newNode  = new PathTreeNode(position, currentNode, weight);

            if (CheckNode != null && !CheckNode(newNode.Position.X, newNode.Position.Y, userData) || AnyNodeIsAtPoint(closedNodes, newNode.Position) || AnyNodeIsAtPoint(openNodes, newNode.Position))
            {
                return(null);
            }

            openNodes.Add(newNode);
            return(newNode);
        }
Пример #5
0
        /// <summary>
        ///     Creates the path.
        /// </summary>
        /// <param name="node">The node.</param>
        /// <param name="depth">An output variable; the depth of the path.</param>
        /// <param name="userData">The user data.</param>
        /// <returns>A list of points defining the found path.</returns>
        private Point[] CreatePath(PathTreeNode node, out int depth, FindPathData userData)
        {
            var output = new List <Point>();
            var parent = node;

            while (parent != null)
            {
                output.Insert(0, parent.Position);
                parent = parent.Parent;
            }

            if (userData != null)
            {
                for (var index = output.Count - 1; index >= 0; --index)
                {
                    var poppingWaypoints = userData.PopWaypointTest(output[index], index);
                    if (!poppingWaypoints)
                    {
                        break;
                    }

                    output.RemoveAt(index);
                }

                if (output.Count == 0)
                {
                    depth = 0;
                    return(output.ToArray());
                }

                if (userData.PopFirstWaypoint)
                {
                    output.RemoveAt(0);
                }

                if (userData.PopLastNWaypoints > 0)
                {
                    if (userData.PopLastNWaypoints > output.Count)
                    {
                        depth = 0;
                        output.Clear();
                        return(output.ToArray());
                    }

                    output.RemoveRange(output.Count - userData.PopLastNWaypoints, userData.PopLastNWaypoints);
                }
            }

            depth = output.Count;

            if (!TrimPaths)
            {
                return(output.ToArray());
            }

            var indicesToRemove = new List <int>();

            for (var index = 1; index < output.Count - 1; ++index)
            {
                var previousPoint = output[index - 1];
                var currentPoint  = output[index];
                var nextPoint     = output[index + 1];

                if (PointsContinueHorizontally(previousPoint, currentPoint, nextPoint) || PointsContinuesVertically(previousPoint, currentPoint, nextPoint) || PointsContinueDiagonally(previousPoint, currentPoint, nextPoint))
                {
                    indicesToRemove.Add(index);
                }
            }

            for (var index = indicesToRemove.Count - 1; index >= 0; --index)
            {
                output.RemoveAt(indicesToRemove[index]);
            }

            return(output.ToArray());
        }
Пример #6
0
        /// <summary>
        ///     Finds the path.
        /// </summary>
        /// <param name="startPosition">The start position.</param>
        /// <param name="endPosition">The end position.</param>
        /// <param name="pathingPolygon">The pathing polygon.</param>
        /// <param name="userData">The user data used when processing nodes.</param>
        /// <returns>A list of points defining the found path.</returns>
        public Path FindPath(Point startPosition, Point endPosition, PathingPolygon pathingPolygon, FindPathData userData)
        {
            var pathPoints = FindPath(startPosition, endPosition, out var depth, userData);

            if (!pathPoints.Any())
            {
                return(new Path());
            }
            var output = new Path
            {
                Depth = depth
            };

            foreach (var(x, y) in pathPoints)
            {
                var node = pathingPolygon.GetNodeAtColumnRow(x, y);
                output.AddWaypoint(node.Bounds.Center.ToVector2(), 0f);
            }

            return(output);
        }
Пример #7
0
 /// <summary>
 ///     Finds the path.
 /// </summary>
 /// <param name="startColumn">The start column.</param>
 /// <param name="startRow">The start row.</param>
 /// <param name="endColumn">The end column.</param>
 /// <param name="endRow">The end row.</param>
 /// <param name="pathingPolygon">The pathing polygon to find the path inside of.</param>
 /// <param name="userData">The user data used when processing nodes.</param>
 /// <returns>A list of points defining the found path.</returns>
 public Path FindPath(int startColumn, int startRow, int endColumn, int endRow, PathingPolygon pathingPolygon, FindPathData userData) => FindPath(new Point(startColumn, startRow), new Point(endColumn, endRow), pathingPolygon, userData);
Пример #8
0
        public Path FindPath(Point startPosition, Point endPosition, PathingPolygon pathingPolygon, FindPathData userData = null)
        {
            int depth;
            var pathPoints = FindPath(startPosition, endPosition, out depth, userData);

            if (pathPoints == null)
            {
                return(null);
            }
            var output = new Path();

            output.Depth = depth;
            foreach (var point in pathPoints)
            {
                var node = pathingPolygon.GetNodeAtColumnRow(point.X, point.Y);
                output.AddWaypoint(node.Bounds.Center.ToVector2());
            }
            return(output);
        }
Пример #9
0
        public Point[] FindPath(Point startPosition, Point endPosition, out int depth, FindPathData userData = null)
        {
            var closedNodes = new List <PathTreeNode>();
            var openNodes   = new List <PathTreeNode>();

            openNodes.Add(new PathTreeNode(startPosition, null, 0));

            while (true)
            {
                if (openNodes.Count == 0)
                {
                    depth = 0;
                    return(null);
                }

                var currentNode     = openNodes[0];
                var currentPosition = currentNode.Position;
                if (!closedNodes.Contains(currentNode))
                {
                    if (currentPosition == endPosition)
                    {
                        return(CreatePath(currentNode, out depth, userData));
                    }

                    PathTreeNode left = null, up = null, right = null, down = null;

                    left  = ProcessNode(currentNode, -1, 0, openNodes, closedNodes, userData);
                    up    = ProcessNode(currentNode, 0, -1, openNodes, closedNodes, userData);
                    right = ProcessNode(currentNode, 1, 0, openNodes, closedNodes, userData);
                    down  = ProcessNode(currentNode, 0, 1, openNodes, closedNodes, userData);

                    if (left != null && up != null)
                    {
                        ProcessNode(currentNode, -1, -1, openNodes, closedNodes, userData);
                    }
                    if (right != null && up != null)
                    {
                        ProcessNode(currentNode, 1, -1, openNodes, closedNodes, userData);
                    }
                    if (right != null && down != null)
                    {
                        ProcessNode(currentNode, 1, 1, openNodes, closedNodes, userData);
                    }
                    if (left != null && down != null)
                    {
                        ProcessNode(currentNode, -1, 1, openNodes, closedNodes, userData);
                    }

                    closedNodes.Add(currentNode);
                }
                openNodes.RemoveAt(0);
            }
        }
Пример #10
0
 public Point[] FindPath(int startColumn, int startRow, int endColumn, int endRow, out int depth, FindPathData userData = null)
 {
     return(FindPath(new Point(startColumn, startRow), new Point(endColumn, endRow), out depth, userData));
 }
Пример #11
0
        private PathTreeNode ProcessNode(PathTreeNode currentNode, int columnOffset, int rowOffset, List <PathTreeNode> openNodes, List <PathTreeNode> closedNodes, FindPathData userData)
        {
            var newNode = new PathTreeNode(currentNode.Position.X + columnOffset, currentNode.Position.Y + rowOffset, currentNode, 0);

            if ((CheckNode == null || CheckNode(newNode.Position.X, newNode.Position.Y, userData)) &&
                !CheckNodeList(closedNodes, newNode.Position) &&
                !CheckNodeList(openNodes, newNode.Position))
            {
                openNodes.Add(newNode);
                return(newNode);
            }
            return(null);
        }