I did notice this some time ago but just swap to timer or use _process(), but I decide to ask:
In this code above, any objects I add to scene are not rendered and never shows, if I put some Timer to spawn it or any other mechanism it works, is this a bug or something that is not documented ?

extends Node
@onready var ballmodel:MeshInstance3D = $"../BallModel"
@onready var rootNode:Node3D = $".."
func _ready():
	var nb = ballmodel.duplicate()
	nb.set_visible( true )
	rootNode.add_child( nb )
  • So I have searched about the call_deferred function, and I came across this interesting Q&A
    At the end of the answer there is this:

    Another usage of call_deferred is to postpone the call of a function instead of executing it immediately, so for example you can use it in _ready to create more child nodes (because at this point the engine is locking the tree).

    So here we have it, although the answer is from 2016 / edited 2018, is this the answer you perhaps were looking for? I don't know if this changed in any more recent versions of Godot.

I'm not super confident in my godot abilities yet but I think I have ran into something like this. The problem for me was that the ballmodel node was above whatever node is creating a copy of it. This matters because the ready functions are called from the bottom to the top, so the ball model might not be ready when you are trying to duplicate it. If you can, move the ball model under this node. Maybe that's not happening here though, but I think the next paragraph will definitely fix it.

Something I feel like I should add, though, is that usually when adding a thing to your game, I think it's best to instance a scene. This can be done fairly easily by right clicking on your ball model in the scene tree and clicking "save branch as scene". Then when you want to add it, call preload("the path to your ball model scene").instantiate(). Then you can add that as a child like you are doing here.

    LiabilityLuke I dont think this is the problem, if it was the problem the code would give a null pointer error...

    I am not sure what is happening and this might be wrong and I might be guessing.
    So try this:

    ballmodel.set_visible(false)

    So what I am thinking, is that when you are duplicating the node, it is appearing just at the same position of the original node. and they "appear" as one.

    You can alternatively if you want to make sure both are present is set the position of the nb:
    nb.position += Vector3(1, 1, 1) or whatever displacement you want.

      BroTa I think _ready is for some reason not able to render anything, its easy to fix like:

      var firstframe:bool=true
      func _process(delta):
      	if(firstframe): _firstframe()
      
      func _firstframe():
      	firstframe=false
      	... do anything you would put in _ready here and it will work ....

      I just wander why is that way, it leads people to mistake, so eater this would need to change, or an _firstframe overrideble function should be created...

      You are right, I just tested that, but in 2D as I am a noob in 3D, but I think the same applies.
      So your explanation of frames make something tick for me.
      So I think I solved it, in 2D at least.
      I used this:

      func _ready():
      	var nb = ballmodel.duplicate()
      	nb.set_visible( true )
      	rootNode.call_deferred("add_child", nb) # This works ...

      And just like magic, it worked haha.
      Seriously I don't understand call_deferred() much it feels like black magic
      Is it calling the method lastly in the current frame? or is there more to it?
      If anyone can explain it I would very much appreciate it.

      So I have searched about the call_deferred function, and I came across this interesting Q&A
      At the end of the answer there is this:

      Another usage of call_deferred is to postpone the call of a function instead of executing it immediately, so for example you can use it in _ready to create more child nodes (because at this point the engine is locking the tree).

      So here we have it, although the answer is from 2016 / edited 2018, is this the answer you perhaps were looking for? I don't know if this changed in any more recent versions of Godot.

        BroTa Not exactly... But I didnt knew about this call_deferred, it seems another solution. But my point here is not exactly a solution since its easy to fix, but on why this happens... If this is a bug or something missing in the documentation, because I could not find anything in documentation on why this happens... I guess I will open a bug report and see what happens...

        BroTa Ha, just notice your reply about changing the position, I tried that didnt work, for some reason the objects seems to exists, and you can move it, but it dont render.

          If you print ballmodel and rootNode in that _ready() function, are the outputs non-null and the expected types?

          Since parents aren't "ready" until after their children, I'm surprised that there are no error messages. That's why call_deferred fixes the problem, since it defers the execution until the first idle frame, and all the nodes are "ready" then.

          IceBergyn the objects seems to exist, and you can move it, but it doesn't render

          That could happen if the object has been created but is not in the scene tree.

          xyz theraot said we should use call_deferred insteed when in ready ( that was what I understood ) , as instated by BroTa. Also, I did notice the error now : Parent node is busy setting up children, add_node() failed. Consider using call_deferred("add_child", child) instead.
          So... I guess that is the way to go... I did notice that it only happens if I use the script in a "Node" object, if I use a Node3D it dont happen... Odd, but if this is the way to go...

          • xyz replied to this.

            IceBergyn The point is that the error message tells you exactly what is happening and why. It even suggests how to "fix" it. So it's important to read and understand error messages.

            The "probelm" will happen with every type of node if you try to add children before the parent node has been fully set up upon run. The node is fully set up when all of its children (as set in the editor) are fully set up. This won't be true if you try to add a child to a parent from the _ready() callback of one of its children. At this point the _ready() of the parent as well as some of the children (depending on the order) have not been executed yet, so the initialization of children is still ongoing, hence "the node is busy setting up children". Using call_deferred() postpones this to immediately after the whole tree has been initialized.

            You can also "fix" it without call_deffered() by running the duplication code in the _ready() callback in a script attached to the parent (instead of a child), because parent's _ready() is called immediately after all children have been set up.

            This whole thing is a consequence of Godot's architecture, i.e. storing scene graphs as trees, which results in a strict hierarchical order of node initialization and script execution.