/// <summary>
        /// Create "fake" Portal Node inside NavArea.
        /// I will auto-link one way to other Portal Nodes. = other Portal Nodes will not be affected, will not know about the links.
        /// </summary>
        public static TNode CreateFakeStartNode(ref Point position, List <TNode> availablePortals)
        {
            var node = _CreateFakeNode(ref position, availablePortals, -1);

            float distanceToTravel;

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

                node._FakeLinkToOneWay(otherPortalNode, distanceToTravel);
            }

            return(node);
        }
        /// <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);
        }
Esempio n. 3
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);
        }
Esempio n. 4
0
        private void _CalculateNeighbors()
        {
#if o
            D.WriteLine(" * NavMesh._CalculateNeighbors()");
#endif
            // Fill out the neighbor information for each NavArea
            // Find and create Portals (Portal Nodes) for each NavArea
            #region
            NavArea <TNode, TLink> navArea;
            NavArea <TNode, TLink> otherNavArea;
            AxisAlignedRectangle   navAreaPolygon;
            AxisAlignedRectangle   otherNavAreaPolygon;
            TNode      portalNode;
            SimpleLine portal;
            int        portalId = 1;
            for (int i = 0; i < _NavAreas.Count; i++)
            {
                navArea        = _NavAreas[i];
                navAreaPolygon = navArea.Polygon;
#if o
                D.WriteLine("   navArea: " + navAreaPolygon.Name);
                //(navArea as PositionedNode).CheckedAsMain = true;
#endif
                for (int j = i + 1; j < _NavAreas.Count; j++)
                {
                    otherNavArea        = _NavAreas[j];
                    otherNavAreaPolygon = otherNavArea.Polygon;
#if o
                    D.WriteLine("     otherNavPoly: " + otherNavAreaPolygon.Name);
#endif
                    #region    - Check polygons distance
                    // Check if the other navpoly is within range to touch
                    // Distance between centers
                    var distanceBetweenCenters = RUtils.Distance2D(ref navAreaPolygon.Position, ref otherNavAreaPolygon.Position);
                    // If Distance between centers is bigger than combined radii, they are not in range
                    // If Distance between centers is smaller or equal, they are in range (not necessarily touching)
                    if (distanceBetweenCenters >= navAreaPolygon.BoundingRadius + otherNavAreaPolygon.BoundingRadius)
                    {
                        // Not in range => proceed to another navpoly
#if o
                        D.WriteLine($"       Not in range (distanceBetweenCenters: {distanceBetweenCenters} totalRadii: {navAreaPolygon.BoundingRadius + otherNavAreaPolygon.BoundingRadius})");
#endif
                        continue;
                    }
#if o
                    D.WriteLine($"       In range (distanceBetweenCenters: {distanceBetweenCenters} totalRadii: {navAreaPolygon.BoundingRadius + otherNavAreaPolygon.BoundingRadius})"); \
                    #endif
                    #endregion - Check polygons distance END

                    // The are in range, so check each edge pairing
                    // to find shared edge and shared part of edges = portal
                    #region    - Using common sense
                    // Here I know they do overlap
                    //      Calculate the portal between the two polygons
                    //      - THIS NEEDS TO BE IN CLOCKWISE ORDER, RELATIVE TO EACH POLYGON
                    // _GetSegmentOverlap()
                    //  returns horizontal: always left-to-right
                    //  returns vertical: always bottom-to-top
                    portal = null;
                    // other is above
                    if (navAreaPolygon.Top == otherNavAreaPolygon.Bottom)
                    {
#if o
                        D.WriteLine($"       Other above -- Touching this Top ({navAreaPolygon.Top}) - other Bottom ({otherNavAreaPolygon.Bottom})");
#endif
                        portal = _GetSegmentOverlap(navArea.EdgeTop, otherNavArea.EdgeBottom, true, false);
#if o
                        // Debug visuals
                        if (portal != null)
                        {
                            //_DrawDebugVisualForPortal(portal.Start.X + 3f, portal.Start.Y - 3f, portal.End.X - 3f, portal.End.Y - 3f);
                            Debug.ShowLine(portal, Color.Yellow);
                        }
#endif
                    }
                    // other is below
                    else if (navAreaPolygon.Bottom == otherNavAreaPolygon.Top)
                    {
#if o
                        D.WriteLine($"       Other below -- Touching this Bottom ({navAreaPolygon.Bottom}) - other Top ({otherNavAreaPolygon.Top})");
#endif
                        portal = _GetSegmentOverlap(navArea.EdgeBottom, otherNavArea.EdgeTop, true, true);
#if o
                        // Debug visuals
                        if (portal != null)
                        {
                            //_DrawDebugVisualForPortal(portal.Start.X - 3f, portal.Start.Y + 3f, portal.End.X + 3f, portal.End.Y + 3f);
                            Debug.ShowLine(portal, Color.Yellow);
                        }
#endif
                    }
                    // other is to left
                    else if (navAreaPolygon.Left == otherNavAreaPolygon.Right)
                    {
#if o
                        D.WriteLine($"       Other to left -- Touching this Left ({navAreaPolygon.Left}) - other Right ({otherNavAreaPolygon.Right})");
#endif
                        portal = _GetSegmentOverlap(navArea.EdgeLeft, otherNavArea.EdgeRight, false, false);
#if o
                        // Debug visuals
                        if (portal != null)
                        {
                            //_DrawDebugVisualForPortal(portal.Start.X + 3f, portal.Start.Y + 3f, portal.End.X + 3f, portal.End.Y - 3f);
                            Debug.ShowLine(portal, Color.Yellow);
                        }
#endif
                    }
                    // other is to right
                    else if (navAreaPolygon.Right == otherNavAreaPolygon.Left)
                    {
#if o
                        D.WriteLine($"       Other to right -- Touching this Right ({navAreaPolygon.Right}) - other Left ({otherNavAreaPolygon.Left})");
#endif
                        portal = _GetSegmentOverlap(navArea.EdgeRight, otherNavArea.EdgeLeft, false, true);
#if o
                        // Debug visuals
                        if (portal != null)
                        {
                            //_DrawDebugVisualForPortal(portal.Start.X - 3f, portal.Start.Y - 3f, portal.End.X - 3f, portal.End.Y + 3f);
                            Debug.ShowLine(portal, Color.Yellow);
                        }
#endif
                    }
                    // not touching
                    else
                    {
                        // Not actually touching => proceed to another navpoly
#if o
                        D.WriteLine($"       Not Touching");
#endif
                        continue;
                    }
                    #endregion - Using common sense END


                    if (portal != null) // this check IS needed
                    {
                        // Found portal between 2 NavAreas
                        // - have to add portal Node
                        portalNode = PortalNodeBase <TLink, TNode> .Create(portalId, navArea, otherNavArea, portal);

                        portalId++;
                        //
                        // - have to link this portal node to all other Portal Nodes in both this and other NavArea
                        //   BUT at this point I dont know all Portal Nodes in this or the other NavArea
                        //   => store both portal lines (sides) in this Portal Node
                        //   => store both NavAreas in this Portal Node
                        //   => do the linking at the end of NavMesh creation
                        //
                        //   - assign Portal Node to this NavArea
                        navArea.Portals.Add(portalNode);
                        //
                        //   - assign Portal Node to other NavArea
                        otherNavArea.Portals.Add(portalNode);
                        //

                        //navArea.LinkTo(otherNavArea, portal);

                        _PortalNodes.Add(portalNode);
#if o
                        #region    -- Debug / visuals
                        Debug.ShowText(ref portalNode.Position, portalNode.ID.ToString());

                        /*Debug.ShowLine(portal, Color.Yellow);
                         * var circle = ShapeManager.AddCircle();
                         * circle.Radius = 6f;
                         * circle.Color = Color.Yellow;
                         * circle.X = (float)portal.Start.X;
                         * circle.Y = (float)portal.Start.Y;
                         * Debug.ShowLine(navAreaPolygon.Position, otherNavAreaPolygon.Position, Debug.Gray32);*/
                        #endregion -- Debug / visuals END
#endif
                    }
#if o
                    else
                    {
                        D.WriteLine($"       Not Touching");
                    }
#endif
                } // for other j
            }     // for one i
            #endregion

            // Link Portal Nodes together inside each NavArea
            #region
            navArea    = null;
            portalNode = null;
#if o
            TNode otherPortalNode = null;
            //D.WriteLine("========== Portals' Linking ==========");
#endif
            for (int i = 0; i < _NavAreas.Count; i++)
            {
                navArea = _NavAreas[i];
#if o
                //D.WriteLine("NavArea Portals: " + navArea.Portals.Count + " " + navArea.Polygon.Name);
#endif
                if (navArea.Portals.Count > 1)
                {
                    for (int iPortalNode = 0; iPortalNode < navArea.Portals.Count; iPortalNode++)
                    {
                        portalNode = navArea.Portals[iPortalNode]; // as TNode;
#if o
                        //D.WriteLine("  PortalNode " + portalNode.ID);
#endif
                        for (int iOtherPortalNode = iPortalNode + 1; iOtherPortalNode < navArea.Portals.Count; iOtherPortalNode++)
                        {
#if o
                            otherPortalNode = navArea.Portals[iOtherPortalNode]; // as TNode;

                            //D.WriteLine("    Links to " + otherPortalNode.ID);

                            portalNode.LinkTo(otherPortalNode, navArea);
#else
                            portalNode.LinkTo(navArea.Portals[iOtherPortalNode], navArea);
#endif
                        }
                    }
                }
            }
#if o
            //D.WriteLine("====================================\n");
#endif
            #endregion

            #region    -- Debug / visuals for links
#if o
            //D.WriteLine("========== Portals' Links ==========");
            Xna.Vector3 linkLineShift = new Xna.Vector3(2f, 2f, 0f);
            foreach (var navAreaa in NavAreas)
            {
                //D.WriteLine("NavArea " + navAreaa.Polygon.Name);

                foreach (var portalNodee in navAreaa.Portals)
                {
                    //D.WriteLine("  PortalNode " + portalNodee.ID);

                    foreach (var link in portalNodee.Links)
                    {
                        Debug.ShowLine(portalNodee.Position + linkLineShift, link.NodeLinkingTo.Position + linkLineShift, Debug.Gray32);

                        //D.WriteLine("    Links to " + link.NodeLinkingTo.ID);
                    }
                }
            }
            //D.WriteLine("====================================");

            /*// Debug
             * var sb = new StringBuilder("--------------\n");
             * PositionedNode cNode;
             * foreach (var tNode in _NavPolygons)
             * {
             *  cNode = tNode as PositionedNode;
             *  sb.Append(tNode.Polygon.Name).Append(" ").Append(cNode.CheckedAsMain).Append(" ").Append(cNode.CheckedAsOther)
             *    .Append(" ").Append(tNode.Links.Count)
             *    .AppendLine();
             * }
             * sb.AppendLine("--------------");
             * D.WriteLine(sb.ToString());*/
#endif
            #endregion -- Debug visuals END
        }