publish: true
aliases:
- Node LifecycleAs far as I can tell from the docs this is the order of events when creating a new node and adding it:
MyObject.new())_init()_enter_tree()
add_Child())_ready(). _init() usually is called after the constructor finishesIt seems that we should assume that _init() will be called after the constructor, but unfortunately Godot doesn't seem to guarantee the order? Read this from the docs
"_init() is Called when the object's script is instantiated, oftentimes after the object is initialized in memory (through Object.new() in GDScript, or new GodotObject in C#). It can be also defined to take in parameters. This method is similar to a constructor in most programming languages."
As for as I can tell from the docs, this is the order of events when instantiating a scene and adding it[1]:
_init() assignment: the property's value is replaced by any assignments made in _init(), triggering the setter.# test is initialized to "one", without triggering the setter.
@export var test: String = "one":
set(value):
test = value + "!"
func _init():
# Triggers the setter, changing test's value from "one" to "two!".
test = "two"
# If someone sets test to "three" from the Inspector, it would trigger
# the setter, changing test's value from "two!" to "three!".
From: Godot notifications — Godot Engine (stable) documentation in English @ User-contributed notes:
There's a gotcha with object initialization. When setting Resource types in the inspector, and leaving all its @exported Variant data members (for example) at default values, the default values will overwrite values set in its _init() function as if they were set via the inspector. Example below:
(https://docs.godotengine.org/en/stable/tutorials/best_practices/godot_notifications.html#init-vs-initialization-vs-export)
class_name MyResource extends Resource
@export var my_int: int = -1
func _init() -> void:
if my_int < 0: my_int = 2
class_name MyNode extends Node
@export var my_resource := MyResource.new()
If my_resource is set in the inspector, MyResource.my_int will be -1. If my_resource isn't set via inspector, it will be 2.
Work-around: Implement a private initialization() function that you call_deferred() at the end of the _init() function. The deferred function will execute after the @export properties are initialized so are overwritten.