Mulitple Children on one variable?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By brangho

Hi :smiley:
I’m new here (and new to Godot). If this post is in the wrong section, I’m very sorry.
While playing around with the information provided by the “Getting Started”-Part of the docs, I came across something i can’t find any explanation/solution for.

The scene has a panel as a parent node with a label and two buttons as children:
PanelNode
----LabelNode
----ButtonNode
----addchild
----SpriteNode

I let one button change the labeltext to the list of children (of the PanelNode I assume).
I let the other button add a sprite as another child.

Now, considering I used the “var SpriteNode” to create a new child I expected that clicking the “addchild”-Button multiple times would cause an error or overwrite the last added Sprite, however, it adds more and more which all should be named “SpriteNode”.

How does this work?
Why does Godot not mind that there are multiple nodes with the same name?
And how do i access the SpriteNodes other than the last one?

The script:

extends Panel


var SpriteNode
var c
func _ready():
	get_node("ButtonNode").connect("pressed", self, "_on_ButtonNode_pressed")
	get_node("addchild").connect("pressed", self, "_on_addchild_pressed")
	add_to_group("enemies")

	
func _on_ButtonNode_pressed():
	c = get_children()
	get_node("LabelNode").text = str(c)

func _on_addchild_pressed():
	SpriteNode = Sprite.new()
	add_child(SpriteNode)

I hope my question is somewhat clear.
Thank you :smiley:

:bust_in_silhouette: Reply From: timothybrentwood
  • How does this work? When you use Sprite.new(), Godot finds a open space in memory and creates a new Sprite object there. SpriteNode is assigned a ‘pointer’ to that space in memory. Based on your code only the last sprite created gets its pointer assigned to SpriteNode
  • Why does Godot not mind that there are multiple nodes with the same
    name? Only the last sprite created is kept track of using the SpriteNode variable. The others only hang around because you add_child(SpriteNode) so that maintains a ‘reference’ to those objects so they don’t automatically get cleaned up.
  • And how do i access the SpriteNodes other than the last one?

like this:

var my_sprites = []
for object in get_children():
    if object.has_method("normal_map"):
        my_sprites.append(object)

the more proper way:

func _on_addchild_pressed():
    SpriteNode = Sprite.new()
    add_child(SpriteNode)
    SpriteNode.add_to_group("sprites")

func give_me_my_sprites():
    return get_tree().get_nodes_in_group("sprites")

Thank you Timothy :smiley: The explanation was very helpful!

However I don’t understand the use of “normal_map”. I looked it up and only found it in context of 2D lighting.
Could you explain this a little further please? :smiley:

brangho | 2021-05-01 17:54

It is a function that only sprites have out of your objects. That way of accessing objects/nodes is useful for ‘duck typing’ (but not necessarily useful for determining if something is a built in Node type):

for object in get_children():
    if object.has_method("walk"):
        object.walk()
    if object.has_method("quack"):
        object.quack()

It doesn’t matter what type of object it is, as long as it has a walk() function it will be commanded to walk similarly for quack(). “If it walks like a duck and it quacks like a duck, then it must be a duck”

timothybrentwood | 2021-05-01 18:17

Thank you :smiley:
I never heard of duck typing, but it makes sense and certainly will help with Python too :smiley:

brangho | 2021-05-01 18:34

:bust_in_silhouette: Reply From: Wakatta

Keen observations and infact Godot does mind about same named nodes and no such thing is possible. What happens is it gets a cool name like @Sprite1@.

The variable used does not become the nodes’s name but rather the nodes’s type does in this case Sprite and you can change this behavior in multiple ways but the easiest is to just assign it directly node.set_name("Spritenode")

Each newly added Sprite node becomes the last one so in your code you’re actually not referencing that one at all. So to access any one of them use get_children()[position]

A quick naming convention for add nodes like this is

func _on_addchild_pressed():
    SpriteNode = Sprite.new()
    add_child(SpriteNode)
    SpriteNode.set_name("SpriteNode" + str(get_children().size))

This way you can use for example get_node("SpriteNode5")

Side Notes:

This can all be further observed in the remote view of the scene dock during gameplay which is located at the top left position by default

Thank you :smiley: I didn’t expect any answer that fast and then I got two^^
This really helps to understand the issue as a whole.

Each newly added Sprite node becomes the last one so in your code you’re actually not referencing that one at all

I might be misunderstanding, but do you mean that the last added sprite can’t be accessed with SpriteNode?
If so, how does the output (text of the LabelNode) of my example give a list with the children and the SpriteNode i the form of:
[[Label:1169], [1170], [1171]. [1301]], [Sprite:1301]

Little side-question: Why do the children in the list count up but then skip 130 numbers?

I hope not to cause any inconvience with these questions!

brangho | 2021-05-01 18:11

No your assumptions are correct the SpriteNode var will be the last. Alternatively you can use get_children()[-1]
The output list of children is Godot’s way of reference counting nodes so when you print a list of nodes you’ll get NodeClass + NodeInstanceID

Those numbers are not related to the list but actually the nodes in the sceneTree hence the unusual numbering.

To know where a node is in the list use get_children().find(SpriteNode)

Wakatta | 2021-05-01 18:26

I think I get it now :smiley:

“Thank you Wakatta” :wink:

brangho | 2021-05-01 18:36