0 votes

As the title says ...

I have a Menu scene that is preloaded and instantiated, but not yet added to the main sceneTree.
In the Menu, I need to get references to buttons, connect their signals to methods, and enable/disable some of the btns.
I usually do stuff like that in _ready(), but since the Menu is not part of the sceneTree, I can't use that.

So : _init().
But is this safe to use ? I know that in other programming languages you shouldn't touch nodes until the nodeTree is ready ...

asked Feb 19, 2019 in Engine by siska (65 points)

I'm not perfectly safe here but are you sure that _ready() isn't called?

https://docs.godotengine.org/en/latest/getting_started/workflow/best_practices/godot_notifications.html

"When instantiating a script or a standalone scene, nodes are not added
to the SceneTree upon creation, so no entertree callbacks trigger.
Instead, only the _init and later _ready calls occur."

As I understand _init() will be callled first for the parent, then for the childs (on _ready it's the other way round AFAIK). So you may not get references to the button in the parents _init()?

But as I said on the begin, I'm not safe on this. If _ready() works, it should be safe to use though.

Yeah, I'm sure _ready() isn't called, but _init() is.
I have Menu instantiated in a global script (autoload), like this :

func _ready():              # global.gd
# preload menu and keep around
var m = preload("res://scenes/Menu.tscn")
menu = m.instance() # this does not trigger Menu._ready() !!!

In Menu.tscn, I have :

func _init():
print("init")    # is called from global.gd

func _ready():
print("ready")   # is NOT called

1 Answer

+2 votes
Best answer

_init() is the constructor and in that sense is supposed to be used for internal state initialization. It's possible to set up the scene from here as well, but there are cleaner alternatives.

The direct and indirect children of the scene's root node receive the PARENTED notification one by one as they are added to the isolated node tree. You can hook into this notification by checking for NOTIFICATION_PARENTED in the _notification() callback:

func _notification(what):
    match what:
        NOTIFICATION_PARENTED:
            print("node added as child to its direct parent")

Nodes are added from top to bottom, depth-first.

Finally, by the same mechanism, the root node of the scene receives NOTIFICATION_INSTANCED once all children have been added to their parents. Since the root node does not have a parent during scene instantiation, it will not receive the NOTIFICATION_PARENTED notification.

answered Feb 19, 2019 by eska (1,034 points)
selected Feb 20, 2019 by siska

Great explanation ! Thank you !

NOTIFICATION_INSTANCED works perfectly for what I want to do.

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.