/// <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); }
/// <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); }
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 }