0 votes

I am running into a problem where my parent will try to set_text() of some labels that are his children, but apparently they are not ready yet which returns "null instance" error and crashes the game.

How do we tell the parent to wait for the children ready signal?

I know that this is the problem, because if I write a script on the child, and call the same function on it's parent using _ready(), it works.

asked Dec 28, 2019 in Engine by The_Black_Chess_King (265 points)

A not ready instance and null instances are different things. You can set variables even before adding an instance to the scene so being ready or not isn't a problem.
Use the remote scene view when the error happens to see if the child really exists.

1 Answer

+1 vote
Best answer

I don't know exactly how your code is structured, but I would advise you to call the function that creates/prepares the labels first and then write your text in those boxes. That way you make sure that the boxes will be ready before you attempt to reference them.

Another way is to use the yield keyword, which waits for a signal before it executes what you want it to execute. More on that here, here and in the docs here.

Your problem could well easily be solved by using the onready keyword before declaring your labels like this:

onready var lbl_foo = $Label_Foo

That way Godot loads the label first before it does anything to it.

Last but not least, you could create a Timer node and use its timeout() signal to execute your functions after some time has elapsed.
I hope these tips help you. But then again I do not know how your code and nodes are laid out.

answered Dec 28, 2019 by johnygames (1,576 points)
selected Dec 28, 2019 by The_Black_Chess_King

Well, I used direct access to these labels, on the parent ready. Like:

func _ready():
    $NAME_ITEM.set_text(str(GLOBAL_ITEMS[ITEM_ID]))

These labels don't change, they are only static texts, but I set them like this because they need to retrieve a data stored in a library. In this case a autoloadd which has all items data.

I am going to experiment more with the yield, as I think it's a better solution. And as well try to reference the labels before-hand with the onready var.

Thank you for your response and the links!

Strangely enough, this type of thing worked:

_ready():
    for node in $Labels.get_children():
            match node.name:
                "TEST_LABEL":nodes.set_text("Cheese with Peanut butter.")

I tried every method mentioned in the answer and some other of my own, but my project didn't liked any. I don't know the reason, it remained a mystery to me.

Also I didn't fully prompt the error, going to put it here,

 0:00:00.840   get_node: Node not found: TEST_LABEL.
  <C++ Error>   Condition ' !node ' is true. returned: __null
  <C++ Source>  scene/main/node.cpp:1381 @ get_node()
  <Stack Trace> Status_UI.gd:18 @ STATUS_UPDATE() 
                Status_UI.gd:14 @ _ready()

And here is the line of code on ready.

$TEST_LABEL.set_text(str(int(GPS.WeightMax)).pad_decimals(1))

IoI found the real culprit, It was my fault, a old node was hidden in the scene lower on the list that was using the same script, and I didn't noticed, but upon simply doing: print(self.name)printed 2 times. So, doing the match:prevented it from crashing, because it works almost like a if.

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.