I am still learning so there is a lot I still don’t know about OOP. I have been trying to understand how instancing and node references work, but I can’t seem to really get it right.
What I ultimately wanted is to make a simple finite state machine. I figured I would create an array to store values from nodes and then call the .min() method to determine which is the lowest and use that to determine the state.
However I ran into a null instance error when I try to store the .value property of a child node.
I have 3 progress bars here and I set the values in the inspector manually.
On line 13, inside the _ready() function I am able to print the value from the progressBar node(s), either by using a $ProgressBar_01.value reference or progress_bar_01.value
However when I try to store the value in a global variable, I get the null instance.
I was able to figure out, that I can declare a local variable inside the _ready() function, but then I can only reference it in lines after I declared it. Which I am sure works as intended. But I don’t know, how can I then use node properties in the future in more complicated scenes?
Will I always have to first get the node values inside the _ready() function for them not to be null? What’s the point then to get the @onready references for nodes? That seems to be a best practice but I don’t see the point other than to make it more convenient, by giving a variable name to it rather than a bulky path…
I was trying to look into this and searched for a long time, but still don’t really understand it. Can someone please explain the principles?
@onready means the variable will be initialized right before _ready, without @onready the variable is initialized much before _ready. Since your variable var pb_03_value is dependent on a child node it too should be tagged @onready. You will have to get node values with @onready or after the _ready function, normal variables will be initialized before the node is part of any scene tree.
Thank you! I added @onready before declaring the array and it works now as I wanted.
But I am still a bit confused. If my progressBar nodes are childs of “Test” and the script is attached to “Test” (the root node of the scene), then shouldn’t the child nodes already be “ready” when their parent enters the scene tree? Why does the _ready() of the root node need to run before I can access the properties of the children?
While tree entry occurs top to bottom (parent then child), the ready notification fires bottom to top, which means a node’s ready function only occurs after all it’s children are ready.
Because all scripts are loaded and var initialization runs before anything is ready, the script is not yet in any scene tree, there are no children at that point.
But in your example you are not referencing a child node: you’re referencing a variable that has not been loaded with anything yet (null)
Maybe it helps if you separate these 2 things:
code
memory
The children are loaded into memory by code somewhere at some stage (instantiation)
When all the children are loaded into memory, the lifecycle function _ready() of the parent gets invoked (by some code somewhere)
At this stage the data (reference to the node memory address) represented by $ProgressBar_01 has been assigned.
You can then read out its value: in the _ready() function. Or by using the @onready annotation delaying your code until this ready lifecycle stage is reached.
If you really need pb_01_value to have global scope for this entire script you can just declare it without assigning it, or assign a default initial value (like zero or minus one). Then once _ready iis called just read out from your ProgressBar then.
But..
Unless you’re going to do something special with that var pb_01_value you may as well drop it, because accessing $ProgressBar_01.value directly throughout your script will protect you from double bookkeeping (value can become different whereas it should always be the same)