Set tiles on runtime quicker

Hello,

I’m trying to create an infinite procedurally generated world which is split in chunks that are generated on runtime, the idea is to run the game on mobile platform.
Currently, I’m doing a simple test that just creates chunks of equal tiles with this code:

    void generateChunk(int idX, int idY)
    {
        RuleTile[] tileArray = new RuleTile[width * height];
        BoundsInt area = new BoundsInt(-width / 2 + idX * width, -height / 2 + idY * height, 0, width, height, 1);

        int k = 0;
        for (int i = 0; i < tileArray.Length; i++)
        {
            k = i / width;

            tileArray[i] = (i+k) % 2 == 0 ? tiles[0] : tiles[1];
        }

        tileMap.SetTilesBlock(area, tileArray);
        Debug.Log("chunk generated");
    }

In the case I’m testing, the code is called every time the player enters a new area based on check of player position, SetTilesBlock is called 3 times at max in the same update cycle for tile arrays of 20x20, setting 1200 tiles each time.

I’ve seen some threads about this but I didn’t find a solution. Apparently SetTiles and SetTilesBlock are faster than SetTile, even with those the game freezes noticeably though, especially when I’m on mobile. And I still need to implement the logic for picking the right tile.

Is there a way to do this operation with multi-threaded code or any other quicker alternative to what I’m doing?

Thanks

break up the loading into a set of smaller areas and load some of them at each update. ‘some of them’ will depend on your app.

I do something like this in my own project, pre-made (as opposed to generated) multilayer tilemap chunks using custom tilemap archives.

I had the similar issue of it taking too long when filling in large areas. For example, to load a 4-layer 16x16 chunk (obv some of the layers are more sparse than others) I found that takes about 0.3 ms approx. This uses the form of Set Tiles that uses TileChangeData.

Unfortunately, for large areas, or loading many chunks into a larger area, you can end up trying to load a bazillion tiles at once which can take longer than an update so you get stutter.

I push the area definitions into a queue of areas to load (defined by a RectInt to keep track of position info) and using Async tasks load N of them at a time.

Solved the issue for me.

you are setting too many tiles at the same time. You need to use setTile to set tiles 1 by 1. Yes setTile is slower than setTiles, BUT you will have to settle for that and use it in a coroutine to slowly set the tiles 1 by 1, you can set like 50 tiles every frame to avoid lag. This will mean that you need to start generating chunks a bit ahead of the player. Youll have to figure this out that way.

Thanks! I followed your method and it’s much quicker now. The code looks like this:

    IEnumerator generateChunkDelayed(int idX, int idY)
    {

        TileBase[] tileArray = new TileBase[maxTilesInParallel];
        Vector3Int[] tilesPos = new Vector3Int[maxTilesInParallel];

        int counter = 0;
        for (int x = -width / 2 + idX * width; x < (width) / 2 + idX * width; x++)
        {
            for (int y = -height / 2 + idY * height; y < (height) / 2 + idY * height; y++)
            {
                // this needs to be changed with the logic for picking the correct tile
                tileArray[counter] = counter % 2 == 0 ? tiles[0] : tiles[1];
                tilesPos[counter] = new Vector3Int(x, y, 0);
                counter++;
                if (counter == maxTilesInParallel)
                {
                    tileMap.SetTiles(tilesPos, tileArray);
                    counter = 0;
                    yield return new WaitForEndOfFrame();
                }
            }
        }
    }