+1 vote

In a game like a roguelike, where a level if fully generated before the player starts playing it, how would I do "background loading" with the function that is generating the level? Since the level generation could be doing several loops to place and modify things across a whole level it does create a noticeable freeze in the game before the level is fully loaded.

Is there a way to have the level still generate as fast as possible and have it not freeze the game, much like background loading does for loading a resource?

in Engine by (666 points)

I didn't do this myself ever but the first thing I woud try is coroutines:


2 Answers

0 votes

You can try something using threads (https://godot.readthedocs.io/en/stable/classes/class_thread.html). For example:

var thread = Thread.new()

func do_stuff(arg):
    var area

    # Expensive operations here

    # Avoid loading when other stuff is happening
    call_deferred("load_area", area)

func load_area(area):
    pass # load the area

func start_load(arg1, arg2):
    if not thread.is_active(): # Can't run on active thread
        thread.start(self, "do_stuff", arg1, arg2)

More complicated solutions may involve the thread-run method emitting a signal or something like that, or a queue of areas to load in case the thread is busy.

by (239 points)

I think this is what I want, to use threads. But I don't really understand how threads work. I have it set up so that all the map creation is done in one function, and use thread.start() to start the function, like in your example.

I'm creating and modifying nodes in the build function. The first thing the function does is instances the base map scene, then I do all the generation, adding more nodes as children of the map, and modifying values. Then in the load function I pass in the completed map node so I can add it as a child to my main game, allowing it to enter the tree and start working.

The problem is it takes a lot longer to build in the thread. Like every time a node is created and added as a child it waits one frame, instead of doing it all as fast as possible. I'm not really sure what I'm doing wrong.

Maybe you could try using dictionaries or arrays to create a virtual "tree" and then commit them all to scene when it's complete? If you are using call deferred also that will cause things to wait a frame or so.

Have you tried to change the thread's priority? Because AFAIK it is set to low by default.

–2 votes

No matter what you do, level generation cannot happen instantly. Since the player must wait until the level generation finishes, a wait is unavoidable.

What you can do instead is create a 'loading' scene, which shows a progress bar while you generate the level. Once the level generation finishes, you can load it & player can start playing.

by (14 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.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.