/// <summary> /// Constructor /// </summary> /// <param name="width">Width in pixels</param> /// <param name="height">Height in pixels</param> /// <param name="g">Game Reference</param> /// <param name="_gw">GameWorld Reference</param> public NavMeshManager(int width, int height, Game g) { nodeList = new List <PolygonNode>(); PolygonNode root = new PolygonNode(new Rectangle(0, 0, width, height)); nodeList.Add(root); game = g; }
/// <summary> /// Returns an array of polygons that form a path /// between the two provided points from start to finish. /// </summary> /// <param name="start">Starting point</param> /// <param name="finish">Finish</param> /// <returns>Path</returns> public PolygonNode[] getPath(Point start, Point finish) { List <PolygonNode> closedSet = new List <PolygonNode>(); List <PolygonNode> openSet = new List <PolygonNode>(); List <PolygonNode> came_from = new List <PolygonNode>(); int g_score = 0; int h_score = getHScore(start, finish); int f_score = 0; PolygonNode endzone = getNodeFromPosition(finish); openSet.Add(getNodeFromPosition(start)); PolygonNode current = openSet.ElementAt <PolygonNode>(0); openSet.Remove(current); closedSet.Add(current); while (true) { if (current == endzone) { break; } foreach (PolygonNode pn in current.getAdjacentNodes()) { if (closedSet.Contains(pn)) { continue; } if (!openSet.Contains(pn)) { openSet.Add(pn); pn.parent = current; } } current = getNodeWithLowestFScore(openSet, g_score, finish); if (current == null) { throw new Exception("There is no spoon."); } openSet.Remove(current); closedSet.Add(current); } List <PolygonNode> output = new List <PolygonNode>(); while (current != null) { output.Add(current); current = current.parent; } output.Reverse(); nullParents(); return(output.ToArray()); }
/// <summary> /// Add a new unwalkable rectangle /// </summary> /// <param name="rect">Rectangle to block.</param> public void addRectangle(Rectangle rect) { tex = game.Content.Load <Texture2D>("White"); PolygonNode[] overlaps = getOverlappingNodes(rect); List <PolygonNode> newNodes = new List <PolygonNode>(); List <Point> vertices = new List <Point>(); addVertex(vertices, new Point(rect.Left, rect.Top)); addVertex(vertices, new Point(rect.Left, rect.Bottom)); addVertex(vertices, new Point(rect.Right, rect.Top)); addVertex(vertices, new Point(rect.Right, rect.Bottom)); foreach (PolygonNode pn in overlaps) { Rectangle oldRect = pn.rectangle; addVertex(vertices, new Point(oldRect.Left, oldRect.Top)); addVertex(vertices, new Point(oldRect.Left, oldRect.Bottom)); addVertex(vertices, new Point(oldRect.Right, oldRect.Top)); addVertex(vertices, new Point(oldRect.Right, oldRect.Bottom)); addOverlapVerts(vertices, oldRect, rect); } Point badPoint = new Point(-1, -1); foreach (Point origin in vertices) { Point left = getClosestLeft(origin, vertices); Point bottom = getClosestBottom(origin, vertices); if (left.Equals(badPoint) || bottom.Equals(badPoint)) { continue; } int width = left.X - origin.X; int height = bottom.Y - origin.Y; Rectangle newRect = new Rectangle(origin.X, origin.Y, width, height); if (rect.Contains(newRect.Center)) { continue; } if (!newRect.Equals(rect)) { PolygonNode newPoly = new PolygonNode(newRect); // newPoly.rectangle.Inflate(1,1); nodeList.Add(newPoly); newNodes.Add(newPoly); } } redoAdj(overlaps, newNodes.ToArray()); foreach (PolygonNode pn in overlaps.ToArray()) { nodeList.Remove(pn); } }
/// <summary> /// Adds each node to the other's adjacency list. /// </summary> /// <param name="p1">First node.</param> /// <param name="p2">Second node.</param> public static void linkPolygons(PolygonNode p1, PolygonNode p2) { if (p1 == p2) { throw new Exception("A polygon can't be adjacent to itself."); } if (!p1.adjacentNodes.Contains(p2)) { p1.addNode(p2); } if (!p2.adjacentNodes.Contains(p1)) { p2.addNode(p1); } }
/// <summary> /// Method for getting the node with the f_score from the given set. /// </summary> /// <param name="set">Nodes to check</param> /// <param name="g_score">Current g_score</param> /// <param name="end">Finish</param> /// <returns></returns> private PolygonNode getNodeWithLowestFScore(IEnumerable <PolygonNode> set, int g_score, Point end) { int lowest = int.MaxValue; PolygonNode pnLowest = null; foreach (PolygonNode pn in set) { int _f = getHScore(pn.rectangle.Center, end) + g_score; if (_f < lowest) { lowest = _f; pnLowest = pn; } } return(pnLowest); }
/// <summary> /// This is not really working it should be the point /// that one should pass through between to polygons. /// </summary> /// <param name="pn1">First Polygon</param> /// <param name="pn2">Second Polygon</param> /// <returns>the sweet spot</returns> public static Point getConnectionPoint(PolygonNode pn1, PolygonNode pn2) { if (pn1 == pn2) { throw new Exception("A node cannot be connected to itself."); } if (!pn1.adjacentNodes.Contains(pn2)) { throw new Exception("These nodes are not adjacent and therefore have no connection point."); } Rectangle r1 = pn1.rectangle; Rectangle r2 = pn2.rectangle; int x = -10; int y = -10; if (r1.Top == r2.Bottom) { y = r1.Top; } if (r1.Bottom == r2.Top) { y = r1.Bottom; } if (r1.Left == r2.Right) { x = r1.Left; } if (r1.Right == r2.Left) { x = r1.Right; } if (x == -10) { int n = (Math.Max(r1.Width, r2.Width) - Math.Abs(r1.X - r2.X)); x = n / 2 + Math.Max(r1.X, r2.X); } if (y == -10) { int n = (Math.Max(r1.Height, r2.Height) - Math.Abs(r1.Y - r2.Y)); y = n / 2 + Math.Max(r1.Y, r2.Y); } return(new Point(x, y)); }
/// <summary> /// Check if two PolygonNodes are adjacent. /// </summary> /// <param name="p1">First Node</param> /// <param name="p2">Second Node</param> /// <returns>True if they are next to each other.</returns> public static bool areTheseAdjacent(PolygonNode p1, PolygonNode p2) { Rectangle r1 = p1.rectangle; Rectangle r2 = p2.rectangle; r1.Inflate(1, 0); if (r1.Intersects(r2)) { return(true); } r1.Inflate(-1, 1); if (r1.Intersects(r2)) { return(true); } r1.Inflate(0, -1); return(false); }
/// <summary> /// Redoes the adjacency's of all of the effected polygons. /// </summary> /// <param name="oldNodes">Nodes to be deleted</param> /// <param name="newNodes">New nodes generated</param> private void redoAdj(IEnumerable <PolygonNode> oldNodes, IEnumerable <PolygonNode> newNodes) { foreach (PolygonNode pnOld in oldNodes) { foreach (PolygonNode pnAdj in pnOld.getAdjacentNodes()) { pnAdj.removeNode(pnOld); foreach (PolygonNode pnNew in newNodes) { if (pnNew == pnAdj) { continue; } if (PolygonNode.areTheseAdjacent(pnNew, pnAdj)) { PolygonNode.linkPolygons(pnNew, pnAdj); } } } } foreach (PolygonNode pn1 in newNodes) { foreach (PolygonNode pn2 in newNodes) { if (pn1 == pn2) { continue; } if (PolygonNode.areTheseAdjacent(pn1, pn2)) { PolygonNode.linkPolygons(pn1, pn2); } } } }
/// <summary> /// Adds an adjacent node from this node. /// </summary> /// <param name="pn">Node to add</param> /// <returns>True</returns> public bool addNode(PolygonNode pn) { adjacentNodes.Add(pn); return(true); }
/// <summary> /// Removes an adjacent node from this node. /// </summary> /// <param name="pn">Node to remove</param> /// <returns>True if it was in the list, false otherwise.</returns> public bool removeNode(PolygonNode pn) { return(adjacentNodes.Remove(pn)); }