#How to deal with pattern matching when procedurally generating chunks

1 messages · Page 1 of 1 (latest)

stone sigil
#

Hi everyone,

I'm not sure if this should go here, but as I still consider myself as a beginner, I will open a post here.
I'm trying to procedurally generate a 2D terrain with a tilemap, I successfully done it with a simple tileset (with chunks), but now I want to introduce my own tileset which has terrain options for auto placing specific tiles when I place a type of tile.
I can clearly see big freezes when I'm trying this (below in my code), where I just generate the final tiles at the end of each chunk generation. Do you know how should I implement it, so it's correctly optimal ?

Thank you !

#

We can't send pieces of code ?

#

So the part of code where I generate my chunk (assuming I'm generating it when it's necessary):

func generate_chunk(chunk_pos : Vector2i) -> void:
    
    var tiles : Dictionary = {"dirt":[], "water":[], "grass":[]}
    
    for y in range(width):
        for x in range(height):
            var noise_pos : Vector2 = Vector2i(x, y) + chunk_pos * 32
            var noise_val : float = abs(noise.get_noise_2d(noise_pos.x, noise_pos.y))
            if noise_val < 0.1:
                tiles["water"].append(chunk_pos * 32 + Vector2i(x, y))
            elif noise_val < 0.15:
                tiles["dirt"].append(chunk_pos * 32 + Vector2i(x, y))
            else:
                tiles["grass"].append(chunk_pos * 32 + Vector2i(x, y))
    
    groundLayer.set_cells_terrain_connect(tiles["dirt"],0,0)
    groundLayer.set_cells_terrain_connect(tiles["grass"],0,1)
    groundLayer.set_cells_terrain_connect(tiles["water"],0,2)
#

And this is how chunk generation is handled each frame :

func _process(delta : float) -> void:
    var cam_pos : Vector2i = camera.position / (32 * 16)
    var chunk_loaded : Array = []
    
    for i in range(-3, 4):
        for j in range(-2, 3):
            if Vector2i(i, j) + cam_pos not in chunks.keys():
                generate_chunk(Vector2i(i, j) + cam_pos)
                chunks[Vector2i(i, j) + cam_pos] = Chunk.new(Vector2i(i, j) + cam_pos)
            chunk_loaded.append(Vector2i(i, j) + cam_pos)
            
    for key in chunks.keys():
        if key not in chunk_loaded:
            remove_chunk(chunks[key])
            chunks.erase(key)
tribal spear
stone sigil
#

So I'm using it and I still get lags, because I use BetterTerrain.update_terrain_something to update the tiles in a specific area (here for each chunk). But it's still laggy, I'm pretty sure I'm doing it wrong.

torpid moon
#

You probably shouldn't call it often, if that's what you're doing.
If you're doing this in a large area, do it during a loading screen. That is what those are for.

tribal spear
stone sigil
stone sigil
torpid moon
#

Assuming you're only doing the necessary updates. The next thing to try is to space the updates accross frames.

stone sigil
#

wdym ?

torpid moon
#

Like, in the loop that places the tiles.
Make it stop after X time passes, then resume the next frame.

#

It is a bit risky, but you can synch it up with signals like get_tree().physics_frame

stone sigil
#

I never heard about this method, before that I wasn't using a game engine for my game, so I implemented myself the pattern matching system based on the saved datas from Tiled, it wasn't laggy when I generated a chunk, Idk how they do it. 🤔

torpid moon
#

There's quite the difference between just moving a couple numbers and strings around vs all the work an engine puts on top. Like the rendering.

Optimization is almost always complicated.

#

There's probably some tutorials online on how to handle chunking of data more performantly.

stone sigil
#

yes, for me to see 0.5s of freeze, it seems a bit weird, without terrain connection, the game is perfectly fine, maybe I need to turn myself to threads ?

tribal spear
#

some of the meganodes in godot cant really run on a thread, or at least not efficiently. Iirc TileMap is - or was - one of them but the better terrain plugin offered this functionality.

stone sigil
#

I just need to find someoe who procedurally generated infinite 2D map, using terrain to connect their tiles.

harsh meteor
#

Have you profiled your code? I understand the slowdown is coming from tilemap stuff, but you shouldn't be speculating what precisely is causing the slowdown

stone sigil
#

I'm not speculating

#

If you comment the part where I connect the tiles (outside the loop), it runs normally

#

A bit strange that nobody ever complained about performance problems when connecting tiles 🤔

harsh meteor
#

There's been plenty of complaints, don't worry. I believe that set_cells_terrain_connect is the problem part, although I suggest using the profiler next time, not just commenting code/evaluating freeze.

Personally, I use BetterTerrain, and it's significantly better than default godot implementation. It has a threaded terrain update method as well, I suggest you look at that.

Aside from that, your options are either: not using terrain and having a custom tile solver or using gdextension to make a faster c++ implementation. There is a BetterTerrain gdextension version, but it hasn't been updated in a bit, and won't work with tilemaplayers