Godot:AutoLoad
lastmod 2022-12-24created 2022-12-218 edits
Singleton
The singleton pattern is a useful tool for solving the common use case where you need to store persistent information between scenes. In our case, it is possible to reuse the same scene or class for multiple singletons as long as they have different names.
Using this concept, you can create objects that:
- Are always loaded, no matter which scene is currently running
- Can store global variables such as player information.
- Can handle switching scenes and between-scene transitions.
- Act like a singleton, since GDScript does not support global variables.
| INFORMATION |
| Godot does not make an autoload a "true" singleton as per the singleton design pattern. It may still be instanced more than once by the user if desired. |
Relationship between autoloads and scenes
When you autoload a script, a Node is created and the script is attached to it. This node is added to the root viewport before any other scenes are loaded.
Godot_singleton_scenetree.png
How to use autoload
To autoload a scene or script, select Project -> Project Settings from the menu and go to the AutoLoad tab.
Godot-autoload_example.png
In the case above, any node can access a singleton named "PlayerVariables" with the following code:
var playerVariables = GetNode<PlayerVariables>("/root/PlayerVariables");
playerVariables.Health -= 10; // Instance field.
If the Enable column is checked (the default), the singleton can be accessed directly without the get_node() function:
Caveats
- Cannot be removed at runtime using
free()orqueue_free().
Custom scene switcher
This tutorial explains how to build a scene switcher using autoloads.
For basic scene switching, you can use the SceneTree.change_scene() method (see SceneTree for details). However, if you need more complex behavior when changing scenes, autoloads provide more functionality.
Global Script
Create a new Global.cs script and register it in AutoLoad.
using Godot;
using System;
public class Global : Godot.Node
{
public Node CurrentScene { get; set; }
public override void _Ready()
{
Viewport root = GetTree().Root;
CurrentScene = root.GetChild(root.GetChildCount() - 1);
}
// 씬을 변경하는 함수가 필요합니다.
// 이 함수는 현재 씬을 해제하고 요청한 씬으로 교체해야 합니다.
public void GotoScene(string path)
{
// 이 함수는 일반적으로 신호 콜백 또는 현재 장면의 다른 함수에서 호출됩니다.
// 이 시점에서 현재 장면을 삭제하는 것은 아직 코드를 실행 중일 수 있으므로 좋지 않은 생각입니다.
// 이로 인해 충돌 또는 예기치 않은 동작이 발생합니다.
// 해결 방법은 현재 장면에서 실행 중인 코드가 없다고 확신할 수 있는 나중으로 로드를 연기하는 것입니다.
CallDeferred(nameof(DeferredGotoScene), path);
}
public void DeferredGotoScene(string path)
{
// 이제 현재 장면을 안전하게 제거할 수 있습니다.
CurrentScene.Free();
// 새 장면을 로드합니다.
var nextScene = (PackedScene)GD.Load(path);
// 새 장면을 인스턴스화합니다.
CurrentScene = nextScene.Instance();
// 루트의 자식으로 활성 장면에 추가합니다.
GetTree().Root.AddChild(CurrentScene);
// 선택적으로, `SceneTree.change_scene()` API와 호환되도록 합니다.
GetTree().CurrentScene = CurrentScene;
}
}
With Object.call_deferred(), the function passed as an argument runs only after all code in the current scene has completed. Therefore, the current scene is not removed while it is still in use (i.e., while its code is still running).
Finally, fill in the empty callback functions in the two scenes:
// Add to 'Scene1.cs'.
public void OnButtonPressed()
{
var global = GetNode<Global>("/root/Global");
global.GotoScene("res://Scene2.tscn");
}
and
// Add to 'Scene2.cs'.
public void OnButtonPressed()
{
var global = GetNode<Global>("/root/Global");
global.GotoScene("res://Scene1.tscn");
}
Run the project and check that the scene switches each time you press the button.
Next steps
If the scene is small, scene switching is fast. However, if the scene is more complex, it may take a considerable amount of time to appear. To learn how to handle this, see the next tutorial, Background loading.
If the loading time is relatively short (less than 3 seconds), you can show a "loading plaque" by displaying some kind of 2D element just before changing the scene. You can then hide it right after the scene has changed. This can be used to let the player know that a scene is being loaded.