Esempio n. 1
0
 public void SetMesh(NavigationMesh[] mesh)
 {
     mMesh = mesh;
 }
Esempio n. 2
0
        /// <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;
        }