Search code examples
xnamonogametileframe-rateisometric

Monogame - Isometric Tiles, low FPS on big maps


i need help with my code on my isometric 2D in Monogame. I have sucessfully created tile engine that renders 500*750 tiles (128x64 size) at 60FPS (but my computer is on fire), but problem is on bigger sizes where FPS goes down a lot.

first i will load all tiles into list of tiles:

for (int i = 0; i < 500; i++)
        {
            for (int j = 0; j < 750; j++)
            {
                int x = j * 128 / 2;
                int y = i * 64;

                int ix = x - y;
                int iy = (x + y) / 2;
                tiles.Add(new Tile("001", new Vector2(ix, iy), new Vector2(j, i), spriteBatch, spriteFont, content));
            }
        }

then when i need to draw i'm colling method that will draw visible tiles:

public void drawMap(Camera camera)
    {
        if (spriteBatch != null)
        {
            tilesDrawed = 0;
            foreach (Tile tile in tiles) // the problem
            {
                if (camera.isTileVisibe((int)tile.position.X, (int)tile.position.Y))
                {
                    Point isoCoords = new Point((int)tile.position.X, (int)tile.position.Y);
                    isoCoords.X -= camera.xOffset;
                    isoCoords.Y -= camera.yOffset;

                    tile.drawTile(isoCoords);
                    tilesDrawed++;
                }
            }


        }
    }

i know that the issue is that i go through every posible tile. But i have no idea how to approach this :/. I was thinking that i will add to the list of tiles only visible ones, but in the end it is the same , i have to go thought all tiles to check if they are visible to the camera.

result: Result

I really need help i'm sitting on this for a long time.

Thank you.

edit: so i replaced my foreach on everytile with only visible ones:

            List<Tile> visibleTiles = tiles.FindAll(r => (
                           (int)r.position.X + 128 > camera.width + camera.xOffset - camera.width && (int)r.position.X - 128 < camera.width + camera.xOffset) &&
                          ((int)r.position.Y + 64 > camera.height + camera.yOffset - camera.height && r.position.Y - 64 < camera.height + camera.yOffset));


            foreach (Tile tile in visibleTiles)
            {
                Point isoCoords = new Point((int)tile.position.X, (int)tile.position.Y);
                isoCoords.X -= camera.xOffset;
                isoCoords.Y -= camera.yOffset;

                tile.drawTile(isoCoords);
                tilesDrawed++;
            }

no help there findAll is slow i think, it is just a bit faster.

i switched to 2d array i need to find visible tiles.. when i'm calculating with:

            int si = (-camera.xOffset - tileWidth) / 64;
            int ei = (-camera.xOffset + camera.width + tileWidth) / 64;
            int sj = (-camera.yOffset - tileHeight) / 64;
            int ej = (-camera.yOffset + camera.height + tileHeight) / 64;

            Point start = twoDToIso(new Point(si,sj));
            Point end = twoDToIso(new Point(ei, ej));

it is little bit off,, if it goes outfobound i will check if tile exist.

I cant figure it out.. sitting here thinking at 3:00 AM


Solution

  • If you want to draw a 2D map, why do you not store it in 2D? A two-dimensional array would be fine for that.

    This way you could calculate which part of the area you want to render and use 2 for loops to iterate through the array.

    Never use LinQ in realtime applications at all, only if you call it for once but not on every draw call.

    You could add a transformation-matrix to your camera so you can skip the movement-addition and instead move the vertices of the tiles by your SpriteBatch.