#Method `find_child()` Doesn't See Everything?

8 messages · Page 1 of 1 (latest)

simple musk
#

(Godot 4.2/GDscript)
When I run my game I have enemies spawning as such: <screenshot>
Why can't 'Main' use find_child() to find the Enemy_1234 objects?
I've tried matching by object name like the docs say, and i've tried just matching by * and printing everything out, but it's like it doesn't see them at all in the tree, even when i specify recursion to be true specifically (although i know it's true by default).
It can see the other obejcts inside "Enemy Things", just not the enemies spawning after launch.

What am I missing, please?

fossil lichen
#

if you spawned enemies by code, I would assume you did not assign them an owner

https://docs.godotengine.org/en/stable/classes/class_node.html#class-node-method-find-children

If owned is true, only descendants with a valid owner node are checked.

https://docs.godotengine.org/en/stable/classes/class_node.html#class-node-property-owner

Note: In the editor, nodes not owned by the scene root are usually not displayed in the Scene dock, and will not be saved. To prevent this, remember to set the owner after calling add_child. See also (see unique_name_in_owner)
this is not directly related, but remember to set the owner after calling add_child sounds like a good idea in general terms

just tested it myself, if I do not set an owner then the function find_children do not retrieve them

extends Node2D

@onready var enemies = $Enemies

func _process(delta: float) -> void:
  if Input.is_action_just_pressed("ui_accept"): //print list when enter pressed
    print(find_children("Enemy*"))
    
  if Input.is_action_just_pressed("ui_cancel"): //add new enemy when escape is pressed
    var node = Node2D.new()
    enemies.add_child(node)
    node.name = "Enemy"
    node.owner = self //without this line, the new ones are not retrieved
#

as the documentation states, that find_child and find_children can be very slow, I would suggest you to have an own parent for just the enemies, so you can use get_children instead of searching for them by name

|- Main
 |- Enemy Things
  |- Enemy Gate Left
  |- Enemy Spawner Left
  |- Enemy Gate Right
  |- Enemy Spawner Right
  |- Enemy Spawn Timer
  |- Enemies
   |- Enemy_1
   |- Enemy_2
   |- Enemy_3

if you set Enemies property % Access as unique name then you could retrieve the list of all enemies like this

@onready var enemies = %Enemies

func some_function() -> void:
  for enemy in enemies.get_children():
    enemy.do_stuff()

if you will have enemies in different parents, then Groups could be interesting for you (https://docs.godotengine.org/en/stable/tutorials/scripting/groups.html)

simple musk
#

Ah! Okay cool, no, I did not set an owner, I was making an assumption (clearly fault on me) that the node spawning an object would be its owner

#

Yeah, I'll probably do:
• groups
class_name
• set owner explicitly
• make Enemies own branch
get_children()

#

Thanks @fossil lichen ! I'll have to try that when I get back home

fossil lichen
simple musk
#

Doing all the bullets above, plus some print()s, really helped me narrow down issues, thanks again!