6
\$\begingroup\$

To my beginner understanding, in order to use a scene saved on the drive, one must first use ResourceLoader.load() to load the scene to acquire a PackedScene, then instantiate it using PackedScene.instance() to acquire the Node that can be finally added as a child.

Following this principle, one can easily export a script String variable and use it to set which scene will be loaded by a node - even with convenient hints like this:

export(String, FILE, "*.tscn") var scene_path

But that's not fully descriptive in my opinion. I want to select a scene - an only scene - in that exported variable. Looking around the internet, this Godot Q&A post mentions one can export a PackedScene variable like any other to link to another scene. So I immediately thought of this:

export(PackedScene) var new_scene = null

This looks much cleaner - especially the ability to initialize it to null, as well as having access to methods like can_instance() to catch any accidental false inputs in the editor... however, this looks like there is one important link of the chain I mentioned at the start missing. In the end, I'm still selecting the PackedScene as a path on disk, so when does the load() happen?

Is this a valid and correct use of the export keyword, or could this come back to haunt me later if I overuse it?

\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

Yes, this is perfectly valid use of export and PackedScene. In fact, you can do this with any Resource (please notice you use a ResourceLoader not a "SceneLoader"). The Resource type has support for serialization and deserialización out of the box.

See When and how to avoid using nodes for everything.


When the game starts it has to load (and instance) the main scene. When you change the scene to another scene, Godot has to load (and instance) that another scene. Or when you tell Godot to load a PackedScene, Godot has to load that scene.

To tell Godot to load a PackedScene you can use preload (loads on parse), ResourceLoader.load, load (simplified ResourceLoader.load), or ResourceLoader.load_interactive (loads in stages to avoid blocking the game while loading large resources, each stage load a subresource).

And if the PackedScene that is being loaded happens to have nodes that export some Resource (such as PackedScene), those has to be loaded alongside too.

That is when the load of the PackedScene happens. I hope that makes sence.


Furthermore, this is not only for PackedScene. You can export any other Resource type, for example export(Shape) works.


Aside, I also want to mention that the editor support for exporting custom resources is not great. If you do export(CustomResource) where CustomResource is a Resource type you created, it won't work. Instead you are forced to do export(Resource), which results in the editor showing all possible Resource types under the sun for you to select.

Workaround:

tool
# …

export(Resource) var variable:Resource setget set_variable
func set_variable(new_value:Resource) -> void:
    if !(new_value is CustomResource): new_value = CustomResource.new()
    variable = new_value

See the proposal Add first-class custom resource support.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ I'm re-reading this again on the next day and I noticed one thing - you said "And if the PackedScene that is being loaded happens to have nodes that export some Resource (such as PackedScene), those has to be loaded alongside too." - that raises a question: Imagine I have a scene that features 10+ buttons to load individual levels. All these buttons have an exported PackedScene variable. Does that mean upon loading the scene with the buttons, Godot loads all the level scenes too? Is there a way to prevent that, other than using exported Strings along with the load() method? \$\endgroup\$ Jul 23, 2021 at 14:37
  • 1
    \$\begingroup\$ @MartyCagas Yes, they load. I should mention that if you have the same PackedScene in multiple places it only loads once. You can use the Profiler and Monitor panels to see how much of an impact that has. Also, below the PackedScene there will be a "Bundled" option where you can see what loads with it, and you will find PackedScenes with their own "Bundled" there. For having control of what to load, using the path is the best way. But there is something else you can do: If those buttons are scenes, you can use "Load As Placeholder" on them, which gives you InstancePlaceholders. \$\endgroup\$
    – Theraot
    Jul 23, 2021 at 19:12

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .