public void SetMesh(NavigationMesh[] mesh) { mMesh = mesh; }
/// <summary> /// After a map has been loaded and all units have been added to the game, /// call this function to freshly create the whole navigation mesh. Be aware that /// this may take a while, depending on the map width and height and on the amount /// of obstructions. /// </summary> public void LoadMeshFromObstructions(int width, int height, int scale) { Rectangle area = new Rectangle(0, 0, width, height); NavigationMesh[] mesh = new NavigationMesh[3]; for (int i = 0; i < 3; i++) { mesh[i] = NavigationMeshFactory.CreateInstanceFromBlockmap(mBlocked[i], new List<Polygon>(), new PointSet<int>(), scale, area, new List<MeshNode>()/*, true*/); } SetMesh(mesh); }
/// <summary> /// For code testing purpose: /// Returns a new special-shaped mesh instance. /// </summary> public static NavigationMesh[] GetTestInstanceForCleanUp() { NavigationMesh[] result = new NavigationMesh[3]; for (int x = 0; x < 3; x++) { MeshNode a = new MeshNode(0, 0); MeshNode b = new MeshNode(0, 10); MeshNode c = new MeshNode(5, 10); MeshNode d = new MeshNode(5, 0); MeshNode e = new MeshNode(0, 15); MeshNode f = new MeshNode(10, 15); MeshNode g = new MeshNode(10, 10); MeshNode h = new MeshNode(15, 15); MeshNode i = new MeshNode(15, 0); MeshNode j = new MeshNode(10, 0); Edge ab = new Edge(a, b); ab.ImposeOwnership(); Edge bc = new Edge(b, c); bc.ImposeOwnership(); Edge cd = new Edge(c, d); cd.ImposeOwnership(); Edge da = new Edge(d, a); da.ImposeOwnership(); Edge be = new Edge(b, e); be.ImposeOwnership(); Edge ef = new Edge(e, f); ef.ImposeOwnership(); Edge fg = new Edge(f, g); fg.ImposeOwnership(); Edge gc = new Edge(g, c); gc.ImposeOwnership(); Edge cb = new Edge(c, b); cb.ImposeOwnership(); Edge fh = new Edge(f, h); fh.ImposeOwnership(); Edge hi = new Edge(h, i); hi.ImposeOwnership(); Edge ij = new Edge(i, j); ij.ImposeOwnership(); Edge jg = new Edge(j, g); jg.ImposeOwnership(); Edge gf = new Edge(g, f); gf.ImposeOwnership(); Polygon pA = new Polygon(new List<Edge> { ab, bc, cd, da }); pA.ImposeOwnership(); Polygon pB = new Polygon(new List<Edge> { be, ef, fg, gc, cb }); pB.ImposeOwnership(); Polygon pC = new Polygon(new List<Edge> { fh, hi, ij, jg, gf }); pC.ImposeOwnership(); result[x] = new NavigationMesh(15,15); result[x].AddPolygon(pA); result[x].AddPolygon(pB); result[x].AddPolygon(pC); } return result; }
/// <summary> /// Returns a new mesh instance. This instance has its polygons auto-generated according to /// the given set "blocked" of impassable (int,int)-points. The largest possibly passable area will be /// a rectangle from (0,0) to (width,height). /// </summary> /// <param name="blocked">contains all integer points that are impassable</param> /// <param name="remainingPolygons">The polygons that still exist within area</param> /// <param name="coveredByPolygonBefore">the nodes that are covered by remainingPolygons</param> /// <param name="scale">the mesh scale</param> /// <param name="area">the area that should be filled with new polygons</param> /// <param name="createdNodes">the still existing nodes that must be integrated</param> /// <param name="unite">if everything in the area should be united at last</param> /// <returns>a new instance of Navigation Mesh that contains all freshly created polygons (but not remainingPolygons)</returns> public static NavigationMesh CreateInstanceFromBlockmap(PointSet<int> blocked, List<Polygon> remainingPolygons, PointSet<int> coveredByPolygonBefore, int scale, Rectangle area, List<MeshNode> createdNodes, bool unite = true) { GlobalValues globalValues = GlobalValues.GetInstance(); PointSet<int> coveredByPremarkedPolygon = new PointSet<int>(); if (globalValues.mShowMeshCreation) { CodeTest.mRects2ToDraw.Add(area); //CodeTest.mSetsToDraw.Add(coveredByPolygonBefore); // slows drawing down for big meshes //CodeTest.mSetsToDraw.Add(coveredByPremarkedPolygon); //CodeTest.mSetsToDraw.Add(blocked); } Debug.Assert(area.Width > 0 && area.Height > 0 && area.X >= 0 && area.Y >= 0); int areaWidth = (area.Width / scale); int areaHeight = (area.Height / scale); int areaOffsetX = (area.X / scale); int areaOffsetY = (area.Y / scale); PointSet<int> nodeToCreate = new PointSet<int>(); PointSet<int> nodeCreated = new PointSet<int>(); foreach (MeshNode node in createdNodes) { int x = ((int)(node.mVector.X)) / scale; int y = ((int)(node.mVector.Y)) / scale; nodeToCreate.Add(x, y); nodeCreated.Add(x, y); } #if DEBUG if (areaWidth < 20 && areaHeight < 20) { Debug.WriteLine("blocked (part):"); NavigationMesh.PrintPointSet(blocked, areaOffsetX, areaOffsetY, areaWidth + 1, areaHeight + 1); } #endif List<Rectangle> premarkedPolygons = new List<Rectangle>(); // a point(a,b) in coveredByPolygon indicates that there is already // a registered polygon which covers at least the square (a,b)-(a+1,b+1) for (int y = areaOffsetY; y < areaOffsetY + areaHeight; y++) { for (int x = areaOffsetX; x < areaOffsetX + areaWidth; x++) { // we wanna create a new rectangular polygon(x,y,*,*) // as big as possible. if (!coveredByPolygonBefore.Contains(x, y) && !coveredByPremarkedPolygon.Contains(x, y) && !blocked.Contains(x, y) && !blocked.Contains(x + 1, y) && !blocked.Contains(x, y + 1) && !blocked.Contains(x + 1, y + 1)) { int polyWidth = 1; int polyHeight = 1; while (x + polyWidth <= areaOffsetX + areaWidth && HorizontalFree(blocked, x, y, polyWidth, polyHeight) && HorizontalFree(coveredByPolygonBefore, x, y, polyWidth - 1, polyHeight - 1) && HorizontalFree(coveredByPremarkedPolygon, x, y, polyWidth - 1, polyHeight - 1) && y + polyHeight <= areaOffsetY + areaHeight && VerticalFree(blocked, x, y, polyWidth, polyHeight) && VerticalFree(coveredByPolygonBefore, x, y, polyWidth - 1, polyHeight - 1) && VerticalFree(coveredByPremarkedPolygon, x, y, polyWidth - 1, polyHeight - 1)) { if (globalValues.mShowMeshCreation) { Rectangle rectToDraw = new Rectangle(scale * x, scale * y, scale * polyWidth, scale * polyHeight); CodeTest.mRectsToDraw.Add(rectToDraw); CodeTest.DrawNow(); CodeTest.mRectsToDraw.Remove(rectToDraw); } polyWidth++; polyHeight++; } polyWidth--; polyHeight--; Debug.Assert(polyWidth > 0 && polyHeight > 0 && polyWidth == polyHeight); // We won't create the polygon now because there is a little // catch (see below), but we are keeping it in mind. // => fill premarkedPolygons now... if (globalValues.mShowMeshCreation) { Rectangle premarkedFullScaled = new Rectangle(scale * x, scale * y, scale * polyWidth, scale * polyHeight); CodeTest.mRectsToDraw.Add(premarkedFullScaled); } Rectangle premarked = new Rectangle(x, y, polyWidth, polyHeight); premarkedPolygons.Add(premarked); // ...and mark nodes as used: nodeToCreate.Add(x, y); nodeToCreate.Add(x + polyWidth, y); nodeToCreate.Add(x + polyWidth, y + polyHeight); nodeToCreate.Add(x, y + polyHeight); // register in coveredByPolygon: for (int i = x; i < x + polyWidth; i++) { for (int j = y; j < y + polyHeight; j++) { coveredByPremarkedPolygon.Add(i, j); } } } } } Debug.WriteLine("premarked polygons:" + premarkedPolygons.Count); if (globalValues.mShowMeshCreation) { for (int i = 0; i < premarkedPolygons.Count; i++) CodeTest.mRectsToDraw.RemoveAt(CodeTest.mRectsToDraw.Count - 1); } // Now that we have full knowledge about ALL nodes to create, we can // create the appropriate polygons. The catch is that sometimes it doesn't // suffice to create the polygon between its corners, but there are polygons // with more vertices in between. int mapWidth = GameLogic.GetInstance().GetMap().GetWidth(); int mapHeight = GameLogic.GetInstance().GetMap().GetHeight(); NavigationMesh result = new NavigationMesh(mapWidth, mapHeight); if (globalValues.mShowMeshCreation) CodeTest.mMeshesToDraw.Add(result); // Create each premarked polygon: foreach (Rectangle rectangle in premarkedPolygons) { List<Point> vertexList = GetVertexList(rectangle, nodeToCreate); Debug.Assert(vertexList.Count >= 4); List<MeshNode> nodes = new List<MeshNode>(); // check which nodes are already created and which need to be created: foreach (Point point in vertexList) { MeshNode node = RetrieveOrCreateNode(point, scale, nodeCreated, createdNodes, remainingPolygons, coveredByPolygonBefore); nodes.Add(node); } // now we can chain up our nodes: Polygon polygon = new Polygon(nodes); polygon.ImposeOwnership(); // add polygon to our mesh: // NOTE: WE MAY NOT ALLOW POLYGON CLEAN UP DURING MESH CONSTRUCTION!!!! // Damn error, I've found you at last... result.AddPolygon(polygon); if (globalValues.mShowMeshCreation) CodeTest.DrawNow(); } // Now unite and clean everything: (At least I think we are allowed now...) if (unite) result.WholeUnionRun(true, null); if (globalValues.mShowMeshCreation) { CodeTest.mMeshesToDraw.Remove(result); CodeTest.mRects2ToDraw.Remove(area); //CodeTest.mSetsToDraw.Remove(coveredByPolygonBefore); // again, taken out for being slow //CodeTest.mSetsToDraw.Remove(coveredByPremarkedPolygon); //CodeTest.mSetsToDraw.Remove(blocked); } return result; }
/// <summary> /// For code testing purposes: /// Creates a raster of polygons where each one is rectangle-shaped and adjacent to each other. /// Note that you have to pass x as countX for x columns of squares, /// the same applies in y direction. The returned mesh then accepts points in the range of /// (0,0)-(cellWidth*countX, cellHeight*countY). /// </summary> /// <param name="cellWidth">the width of each polygon</param> /// <param name="cellHeight">the height of each polygon</param> /// <param name="countX">the number of polygons to create in horizontal direction</param> /// <param name="countY">the number of polygons to create in vertical direction</param> /// <param name="doUnite">if the polygons should be united where possible (reduces raster complexity)</param> /// <returns>the new mesh instance</returns> public static NavigationMesh[] GetTestInstance(int cellWidth, int cellHeight, int countX, int countY, bool doUnite) { Debug.Assert(countX >= 1 && countY >= 1 && cellWidth > 0 && cellHeight > 0); NavigationMesh[] testMesh = new NavigationMesh[3]; for (int i = 0; i < 3; i++) { testMesh[i] = new NavigationMesh(countX * cellWidth, countY * cellHeight); MeshNode[,] nodes = new MeshNode[countX + 1, countY + 1]; for (int x = 0; x <= countX; x++) { for (int y = 0; y <= countY; y++) { nodes[x, y] = new MeshNode(x * cellWidth, y * cellHeight); } } for (int x = 0; x < countX; x++) { for (int y = 0; y < countY; y++) { List<Edge> edges = new List<Edge> { new Edge(nodes[x, y], nodes[x + 1, y]), new Edge(nodes[x + 1, y], nodes[x + 1, y + 1]), new Edge(nodes[x + 1, y + 1], nodes[x, y + 1]), new Edge(nodes[x, y + 1], nodes[x, y]) }; foreach (Edge edge in edges) { edge.ImposeOwnership(); } Polygon polygon = new Polygon(edges); polygon.ImposeOwnership(); testMesh[i].AddPolygon(polygon); } } if (doUnite) { testMesh[i].WholeUnionRun(true, null); } } return testMesh; }