Early initialization of instantiated scene #5718
Replies: 2 comments 5 replies
-
I'm using "NOTIFICATION_INSTANCED" a lot in TailQuest, I think it's the best place to do internal initialization of a scene, in many cases it helped to prevent a lot of issues with setters and getters not being able to operate properly (since some dependent members are not initialized yet) |
Beta Was this translation helpful? Give feedback.
-
I want to comment on the "try to solve" code you have. My current approach for reusable custom nodes (not for scenes) is to have a method that does all the initialization, and:
This way if I'm setting/changing things before adding to (or while removed from) the scene tree, it is storing the changes but not acting on it until it enters the scene tree. But if it is inside the tree, then it will act on the changes right away. Furthermore, it will not act on the changes twice, nor I duplicate that code. I want to emphasize that this approach allows me to remove the node, modify the values and add it again. I'm not saying you should use this for scene (I reiterate it is for reusable custom nodes). But I'm saying you can "try to solve" better. Don't straw man the "try to solve". Addendum: it can get complex to know changes has been applied, for example if you have an array property where the elements can change. With that said, yes, the instant you are looking for is the instanced notification. It is a very good place for scene initialization. |
Beta Was this translation helpful? Give feedback.
-
Node._scene_instantiated()
method and@oninstantiated
annotation godot#87594See also:
Summary
In some cases,
@onready
variables, virtual methods_enter_tree
and_ready
are too late and_init
is too early. Add an annotation and/or a virtual method to early initialize the instantiated scene (before_enter_tree
and_ready
) or properly document the current solution withNOTIFICATION_SCENE_INSTANTIATED
. Pay attention to the issue of scene and class relationships (related #1935).Example
Let's say we want to create a control like this:
When you select an item in
Items
(ItemList
), information about it inItemInfo
is updated. Let's also assume that this control is the base for other controls, and the set of item action buttons may differ in different controls.The first version of our script will look like this:
This works great in most cases, but what happens if we create an
ItemStorageControl
from code?1In the Godot source code, when initializing composite nodes and not only, the approach of describing and adding all child nodes is used, for example:
In GDScript you can do the same thing: add nodes in
_init
and they will be available immediately, before_enter_tree
and_ready
. This can be used in simple cases (few child nodes, few properties to set up), but it is impractical in complex ones: it is more convenient to edit the scene in the editor.You can try to "solve" it like this:
However, this is the wrong approach: duplication of the
title
value, redundant and more confusing code. Especially if you try to do the same with buttons.In #1935, another workaround is mentioned: store the scene body in the scene file, instantiate the scene in
_init
of the class and add it as a child.But the use case for
NOTIFICATION_SCENE_INSTANTIATED
seems to me the most correct. The notification is sent the moment the scene is instantiated (only on the scene's root, which is theowner
of all other scene nodes), well before_enter_tree
and_ready
, but later than_init
(which is called when the root is initialized, before the other nodes are added as children or perhaps even created).Proposal?
Similar to
@onready
and_ready
, we could add an annotation and/or a virtual method:But I'm not sure if this is necessary. Firstly, the name is quite long (is there a short but not confusing one?). Secondly, this method cannot be a replacement for
_ready
, as it is only called when the scene is instantiated (NOTIFICATION_SCENE_INSTANTIATED
not sent to child nodes of the scene or if the node is created vianew()
). In contrast,_init
is always called when an object is created, and_ready
is always called when a node becomes "ready" (roughly equals "first enters the tree").Since the solution already exists (just not documented in detail), I start this discussion rather than opening a proposal. The question is, do we need a separate virtual method instead of using
_notification
2 (which is called in other cases as well, likeNOTIFICATION_PROCESS
if processing is enabled)?But I think that in some cases people may be interested in early initialization of the scene. And this approach is not covered in the documentation. Also, this is another case at the intersection of scenes and classes, and if we implement #1935, then this case should also be taken into account.
Footnotes
instantiate
is a static method that instantiates the scene of the class.See Add scene binding for optional tight-coupling between Node-extending Scripts and PackedScene resources #1935 for details. ↩
See also Really need Node destroy callback function, just like "OnDestroy" in Unity #707. ↩
Beta Was this translation helpful? Give feedback.
All reactions