In a game I'm developing with C# in Godot 3.2.3, I have a main menu, where I have a button that should start a new game. Now, my game is based on maps, which have a lot of resources like units, tilemaps, and more. I guess that by that last fact, when I start a game, the game window freezes for a while saying that is not responding, until the map loads. According to me, this happens 'cause the game is loading the scene.

Based on this idea, I read the Godot Docs, specially this one: https://docs.godotengine.org/en/stable/tutorials/io/background_loading.html#doc-background-loading Unfortunately, this one was written in GDScript, so I couldn't follow it the same way, but I tried to make a C# approach, that lead me to the code at the bottom. However, this did not behaved as I expected. I discovered that the code that avoids my map to load is the currentScene.QueueFree(). Without this one, the map loads, but the code is useless, since again the game freezes with the "no responding" warning and with currentScene.QueueFree(), my map is never going to load.

Does anyone knows something about the matter? Any experience? I thank in advance your support.

StartMenu.cs:

using Godot;
using System;

public class StartMenu : CanvasLayer
{
    public ResourceInteractiveLoader loader = null;
    float maxTime = 150;
    int waitFrames = 0;
    float progress = 0;
    Node currentScene;

    // Called when the node enters the scene tree for the first time.
    public override void _Ready()
    {
        var root = GetTree().Root;
        currentScene = root.GetChild(root.GetChildCount() - 1);
    }

    public void _on_StartButton_pressed()
    {
        loader = ResourceLoader.LoadInteractive("res://scenes/PlayMap.tscn");
        if (loader == null)
        {
            GD.Print("Scene Error");
            return;
        }
        SetProcess(true);
        currentScene.QueueFree();

        var loading = GetNode<AnimatedSprite>("Loading");
        loading.Animation = "loading";
        loading.Play();

        waitFrames = 1;

    }

    public void UpdateProgress()
    {
        progress++;
        GD.Print(progress);
    }

    public void SetNewScene(Resource sceneResource)
    {
        var newScene = sceneResource as PackedScene;
        currentScene = newScene.Instance();
        GetTree().Root.AddChild(currentScene);
    }

    // Called every frame. 'delta' is the elapsed time since the previous frame.
    public override void _Process(float delta)
    {
        if (loader == null)
        {
            SetProcess(false);
            return;
        }

        if (waitFrames > 0)
        {
            waitFrames -= 1;
            return;
        }

        var t = OS.GetTicksMsec();

        while (OS.GetTicksMsec() < t + maxTime)
        {
            var err = loader.Poll();
            if (err == Error.FileEof)
            {
                var resource = loader.GetResource();
                loader = null;
                SetNewScene(resource);
                break;
            }
            if (err == Error.Ok)
            {
                UpdateProgress();
            }
            if (err != Error.Ok && err != Error.FileEof)
            {
                GD.Print(err);
                loader = null;
                break;
            }
        }
    }
}
a month later

I would love to know this answer to this as well. I am getting the same problem.

What node is the C# script attached to? Is it an autoload/singleton or a node in a scene? If its a node in a scene, it could be that the QueueFree call is deleting the node before it has a chance to load the scene, which could be why its not working.

6 days later

TwistedTwigleg, Thank you for your help. I notice that you try to help a lot on the forum.

After a lot of testing, I found that loading a scene in the background is best done with a new thread. I used the "best answer" to THIS POST to pattern a solution in C#.

2 years later