0 votes

I'm attempting to create a chunk generation system for my game for a randomized world. The code I used was originally from this tutorial: https://www.youtube.com/watch?v=rWeQ30h25Yg but I've made some changes as originally the supplied function that'd get what chunks to generate around the player, and then pass that to a separate thread to generate them would only run once (As in it'd only generate 1 chunk even though 20 chunks needed to be generated).

I managed to get it working by implementing a simple for loop that is ran by the thread. This function will be called whenever the player enters a new chunk:

func GenerateChunks():
var player_position = player.position / 32;
var player_x = int(player_position.x) / chunk_size;
var player_y = int(player_position.y) / chunk_size;

xRange = range(player_x - chunk_amount, player_x + chunk_amount);
yRange = range(player_y - chunk_amount, player_y + chunk_amount);

for x in xRange:
    for y in yRange:
        var key = str(x) + "," + str(y); #The key for each Chunk (The Identifier)
        unready_chunks[key] = Vector2(x, y);

        var chunk = GetChunk(x, y);
        if chunk != null:
            chunk.should_remove = false;
        pass
    pass

if not thread.is_active():
    thread.start(self, "CreateChunks", [thread]);
pass

It'll basically work out the chunks meant to be around the player, add them to a dictionary and then start a thread to generate them. This Thread runs this CreateChunks function:

func CreateChunks(thread):
for key in unready_chunks:
    var x = unready_chunks[key].x;
    var y = unready_chunks[key].y;

    var chunk = Chunk.new(noise, x * chunk_size, y * chunk_size, chunk_size, map);
    chunk.position = Vector2(x * chunk_size, y * chunk_size);

    unready_chunks[key] = chunk;
    pass

call_deferred("LoadDone");
pass

Which will actually create the chunk object, reassign the values within the dictionary and call the LoadDone function to end the thread.

func LoadDone():
for chunk in unready_chunks.values():
    add_child(chunk); #Adds the Chunk to the Child object in the scene

    var key = str(chunk.position.x / chunk_size) + "," + str(chunk.position.y / chunk_size);
    chunks[key] = chunk;
    unready_chunks.erase(key);
    pass

thread.wait_to_finish();
pass

This then loops through those created chunks again, adds them as a child to the world object and adds the chunk to another dictionary that stores the generated chunks.

This all works fine but the issue I'm having is with removing chunks that are meant to be out of range of the player. Along with the GenerateChunks function, these two functions are also called:

func CleanUpChunks():
for key in chunks:
    var chunk = chunks[key];
    if chunk.should_remove:
        chunk.Remove();
        chunk.queue_free();
        chunks.erase(key);
    pass
pass

func ResetChunks():
for key in chunks:
    chunks[key].should_remove = true;
    pass
pass

This should set all chunks to be removed unless specified by the GenerateChunks function. The issue though is only ONE chunk is set to be removed when there should be multiple. It's clearly got something to do with my new thread system as the original code I got from that video had the GenerateChunks function called every frame. I've replaced that function with this one instead that'll check differences in the players position to know when to generate new chunks:

func CheckForNeededChunkGeneration():
var player_position = player.position / 32;
var player_x = int(player_position.x) / chunk_size;
var player_y = int(player_position.y) / chunk_size;

var xRangeTemp = range(player_x - chunk_amount, player_x + chunk_amount);
var yRangeTemp = range(player_y - chunk_amount, player_y + chunk_amount);

if xRange != xRangeTemp or yRange != yRangeTemp:
    GenerateChunks();
    CleanUpChunks();
    ResetChunks();
    pass
pass

Wasn't exactly sure how to word all of this so if you have any questions then please ask. I'm just wondering if anyone by chance has any clue to why this is happening with only one chunk being removed at a time.

asked Jan 6 in Engine by codelyoko373 (26 points)
edited Jan 6 by codelyoko373

1 Answer

0 votes

Hi, I just started godot, so not sure how helpful I'll be (also using c# not gdscript....)

anyway, I suggest you get this working WITHOUT threads. then add threads.

as to speculate what's wrong:

I am guessing that the first time through your CheckForNeededChunkGeneration() method, RestChunks() is called and it works properly (some number of chunks flagged for delete)

the second pass through CheckForNeededChunkGeneration() then CleanUpChunks(); is stalling out on the first chunk it deletes. you could easily verify this by logging how many times through the loop it gets.

answered Jan 6 by Jason Swearingen (213 points)
Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.