Generating a tile one frame at a time

Hello! I am experimenting with procedural generation and I’m using code from a youtube tutorial. Everything is great except it generates all unloaded tiles in one frame, which lags the game. I would like to make it so I can only generate one (the closest unactivated) tile per frame. Here is the current script:

List<GameObject> tileObjects = new List<GameObject>();
//activate new tiles
foreach (Vector2 tile in centerTiles)
{
    int radius = isPlayerTile ? radiusToRender : 1;
    for (int i = -radius; i <= radius; i++)
        for (int j = -radius; j <= radius; j++)
            ActivateOrCreateTile((int)tile.x + i, (int)tile.y + j, tileObjects);
}

centerTiles is a list of all tile indexes which are inside the player’s render radius.
The radius is more like a box, not a circle.
isPlayerTile is the tile the player is currently standing on.

Any help with this is greatly appreciated! Thanks!

Stick it in a coroutine and yield after creating a tile.

3 Likes

I actually figured this out myself. Long story short, I stuck it in a coroutine and that increased performance dramatically, but the tiles loaded from -x to +x instead of starting at the players position and working outward (which was the main thing I was struggling with). I eventually figured it out though. If people want to know how I solved this, just shoot me a reply.

Probably worth at least summarizing the method for posterity. You don’t want to be that guy! :smile:

Couldn’t you just generate one tile per each call of Update(), since Update() is called once per frame?

You could, but it would be more awkward as the state for said Update logic would necessarily spill into the body of the class. A coroutine allows the state to be nicely packaged inside a method.

1 Like

Alright, after some refining here is the final code. This is just in my Update loop after getting coordinates of the tiles that need to be loaded.

float tileDistance;
// will be used to test the distance from the player
float shortestDistance = -1;
// set to -1, since distances are always >= 0. this is just to test if shortestDistance is undefined
Vector2 tileToLoad = new Vector2();
// declare the vector that tells which tile to load
bool tileToLoadChanged = false;
// used to tell if a tile has been chosen by the foreach loop

foreach (Vector2 potentialTile in tilesToLoad)
// tilesToLoad is a List<Vector2> of the coordinates of all the tiles inside the render distance that haven't been loaded yet
{
    tileDistance = Vector2.Distance(potentialTile, playerTile);
    // set the distance from the tile to the tile the player is on

    if (tileDistance <= shortestDistance || shortestDistance == -1)
    // check if the new tile distance is shorter than the previous shortest distance, and also if shortestDistance is undefined
    {
        shortestDistance = tileDistance;
        // set the new shortest distance
        tileToLoad = potentialTile;
        // tile will be loaded after the foreach loop has completed
        tileToLoadChanged = true;
        // set to true because we now have coordinates for the tile to load
    }
}

if (tileToLoadChanged)
{
    ActivateOrCreateTile((int)tileToLoad.x, (int)tileToLoad.y, tileObjects);
    // create the tile!
}

Hope this helps!

1 Like