/// <summary>Creates a new PositionedNode.</summary>
        public static TNode Create(int id, NavArea <TNode, TLink> parentNavArea, NavArea <TNode, TLink> otherParentNavArea, SimpleLine portalForFirstParent)
        {
            Point portalCenter = _LineCenter(portalForFirstParent);

            var node = new TNode();

            node.mID = id;

            node.mParentNavArea1 = parentNavArea;
            node.mParentNavArea2 = otherParentNavArea;

            node.mPortalSide1             = portalForFirstParent;
            node.mPortalSide1ParentAreaId = parentNavArea.ID;
            node.mPortalSide2             = NavMesh <TNode, TLink> ._GetInvertedLine(portalForFirstParent);

            node.mPortalSide2ParentAreaId = otherParentNavArea.ID;

            node.Position.X = (float)portalCenter.X;
            node.Position.Y = (float)portalCenter.Y;
            //node.mActive = true;

            return(node);
        }
Beispiel #2
0
        /// <summary>Goes through all Nodes and ties to find Node which rect the point is inside of.</summary>
        /// <returns>Node of which rect the point is inside of, or null if point is not inside any node's rect.</returns>
        public NavArea <TNode, TLink> FindNavRectFromPoint(ref Point point)
        {
            NavArea <TNode, TLink> containingNavArea = null;
            double bestDistance = double.PositiveInfinity;
            double d;
            float  r;

            // Find the closest poly for the starting and ending point
            foreach (var navArea in _NavAreas)
            {
                r = navArea.Polygon.BoundingRadius;
                // Start
                d = RUtils.Distance2D(ref navArea.Polygon.Position, ref point);
                if (d <= bestDistance && d <= r && navArea.Polygon.IsPointInside((float)point.X, (float)point.Y)) // @
                {
                    containingNavArea = navArea;
                    bestDistance      = d;
                }
            }

            // No matching polygons locations for the point (so no path can be found)
            // = point not on nav mesh
            return(containingNavArea);
        }
 public SimpleLine GetPortalSideFor(NavArea <TNode, TLink> navArea)
 {
     return(GetPortalSideFor(navArea.ID));
 }
        /// <summary>
        /// - Create "fake" Portal Node in the "middle" of NavArea.
        /// - Tell all Portal Nodes in containing NavArea to link (one way) to the new fake Node.
        /// = other Portal Nodes will create links to this fake Node.
        ///   CleanupFakeEndNodeLinks() has to be called after fake Node is not needed anymore to remove those "fake" links.
        /// </summary>
        /// <param name="position"></param>
        /// <param name="availablePortals"></param>
        /// <param name="containingNavAreaID"></param>
        /// <returns></returns>
        public static TNode CreateFakeEndNode(ref Point position, List <TNode> availablePortals, NavArea <TNode, TLink> containingNavArea)
        {
            var fakePortalNode = _CreateFakeNode(ref position, availablePortals, -2);

            float distanceBetweeNodes;

            foreach (var otherPortalNode in availablePortals)
            {
                distanceBetweeNodes = (float)RUtils.Distance2D(ref fakePortalNode.Position, ref otherPortalNode.Position);

                otherPortalNode.LinkToOneWay(
                    fakePortalNode,
                    distanceBetweeNodes,         // cost
                    // Add real portal line here.
                    containingNavArea
                    );
            }

            return(fakePortalNode);
        }
        /// <summary></summary>
        /// <param name="position">World position of this fake Node.</param>
        /// <param name="availablePortals">Portals leading out of NavArea this fake Node is positioned in.</param>
        /// <param name="containingNavArea">NavArea this fake Node is positioned in.</param>
        public static TNode CreateFakeNodeDebug(ref Point position, List <TNode> availablePortals, bool isEndNode, NavArea <TNode, TLink> containingNavArea)
        {
            TNode node;

            if (isEndNode)
            {
                node = CreateFakeEndNode(ref position, availablePortals, containingNavArea);
            }
            else
            {
                node = CreateFakeStartNode(ref position, availablePortals);
            }

            node.mParentNavArea1 = containingNavArea;
            node.mParentNavArea2 = containingNavArea;

            return(node);
        }
Beispiel #6
0
        /// <summary>Find a path from the start point to the end point using this nav mesh.</summary>
        /// <param name="startPoint"></param>
        /// <param name="endPoint"></param>
        /// <param name="drawPolyPath">Whether or not to visualize the path through the polygons - e.g. the path that astar found.</param>
        /// <param name="drawFinalPath">Whether or not to visualize the path through the path that was returned.</param>
        /// <returns>An array of points and nodes if a path is found, or nulls if no path</returns>
        public List <Point> FindPath(Point startPoint, Point endPoint, out List <TNode> portalNodesPath
                                     /*, bool drawPolyPath = false, bool drawFinalPath = false*/)
        {
            #region    --- Find the closest poly for the starting and ending point
            NavArea <TNode, TLink> startArea = FindNavRectFromPoint(ref startPoint);
            NavArea <TNode, TLink> endArea   = FindNavRectFromPoint(ref endPoint);

            // No matching polygons locations for the start or end, so no path found
            // = start or end point not on nav mesh
            if (startArea == null || endArea == null)
            {
                portalNodesPath = null;
                return(null);
            }

            // If the start and end polygons are the same, return a direct path
            if (startArea == endArea)
            {
                List <Point> pointsPath = new List <Point> {
                    startPoint, endPoint
                };
                //if (drawFinalPath) this.debugDrawPath(phaserPath, 0xffd900, 10);
                portalNodesPath = null; // not traversing any Portal Nodes
                return(pointsPath);
            }
            #endregion --- Find the closest poly for the starting and ending point END



            #region    --- A* search
            // --- Search!
            portalNodesPath = new List <TNode>();
            GetPath(
#if DEBUG
                PortalNodeBase <TLink, TNode> .CreateFakeNodeDebug(ref startPoint, startArea.Portals, false, startArea),
                PortalNodeBase <TLink, TNode> .CreateFakeNodeDebug(ref endPoint, endArea.Portals, true, endArea),
#else
                PortalNodeBase <TLink, TNode> .CreateFakeStartNode(ref startPoint, startArea.Portals),
                PortalNodeBase <TLink, TNode> .CreateFakeEndNode(ref endPoint, endArea.Portals, endArea),
#endif
                portalNodesPath
                );

            if (portalNodesPath.Count == 0)
            {
                // While the start and end polygons may be valid, no path between them

                portalNodesPath = null;
                return(null);
            }
            #endregion --- A* search END



            #region    --- Funnel algorithm
            // We have a path, so now time for the funnel algorithm
#if o
            D.WriteLine("======== Path search ========");
            D.WriteLine("  --- Path ---");
            foreach (var pathNode in portalNodesPath)
            {
                D.WriteLine("    " + pathNode.ID);
            }
            D.WriteLine("  --- Channel ---");
#endif
            Channel channel = new Channel();
            channel.Add(startPoint);

            SimpleLine portal;
            int        countLimit = portalNodesPath.Count - 1;
            TNode      pathPortalNode;
            TNode      nextPathPortalNode;
            for (int i = 1; i < countLimit; i++) // skipping first Node - I don't need it's Links - I don't need their Portals
            {
                pathPortalNode     = portalNodesPath[i];
                nextPathPortalNode = portalNodesPath[i + 1];
#if o
                D.WriteLine($"    pathPortalNode: {pathPortalNode.ID} and pathPortalNode: {nextPathPortalNode.ID}");
#endif
                // Find the portal
                portal = null;
                foreach (var link in pathPortalNode.Links)
                {
                    //if ( link.NodeLinkingTo.ReferenceEquals(nextPathPortalNode) )
                    if (link.NodeLinkingTo.ID == nextPathPortalNode.ID)
                    {
#if o
                        D.WriteLine($"      link to {link.NodeLinkingTo.ID} - link found and portal added");
#endif
                        portal = link.Portal;
                        // Push the portal vertices into the channel
                        channel.Add(portal.Start, portal.End);
                        break;
                    }
#if o
                    else
                    {
                        D.WriteLine($"      link to {link.NodeLinkingTo.ID} - link NOT found !");
                    }
#endif
                }
            }

            channel.Add(endPoint);


            // Pull a string along the channel to run the funnel
            channel.StringPull();

            PortalNodeBase <TLink, TNode> .CleanupFakeEndNodeLinks(endArea.Portals);

            // Clone path, excluding duplicates - needed ? @
            Point?       lastPoint       = null;
            List <Point> finalPointsPath = new List <Point>();
            foreach (var point in channel.Path)
            {
                //var newPoint = p.clone();
                var newPoint = point;
                //if (!lastPoint || !newPoint.equals(lastPoint))
                if (lastPoint.HasValue == false || newPoint != lastPoint)
                {
                    finalPointsPath.Add(newPoint);
                }
                lastPoint = newPoint;
            }

            return(finalPointsPath);

            #endregion --- Funnel algorithm END
        }