find_node returns weird name?

kyelwkyelw Posts: 6Member

I don't think find_node works the way I expect, so I wonder if someone can point out where I am mistaken:

Here's the code:

    for i in range(1,total_items):
        print("item = ",i)
        var match = 0
        var slot_match = "slot%s" % [i]
        print("search = ",slot_match)
        if (find_node(slot_match)):
            print("found a match!")
            match = 1

        if ! (match == 1):
            print("making a new child: slot",i)
            var slot = slot_class.new()

         get_node("inventory").add_child(slot)
            slot.set_name("slot%s" % slot.number)
            print("new slot name: ",slot.get_name())

Here's the output:

        item = 1
        search = slot1
        making a new child: slot1
        new slot name: slot1
        slot_name = slot1

        item = 1
        search = slot1
        making a new child: slot1
        new slot name: @slot1@4
        slot_name = @slot1@4

It looks to me that it creates the first node, but when I search for it, it
can't find it. But when I try to set the name to be "slot1", it creates it with a new name because slot1 is already taken.

Any help would be appreciated, thanks!

Answers

  • razvanc-rrazvanc-r Posts: 84Member

    There's something in your code that you didn't copy in the post, it's impossible for i to have the same value for two consecutive loops which is what you have in the output. Yes, godot has internally that weird naming convention for when you add nodes with the same name or when you want to change the name of a node to a name that is already taken. Also your code is... well you have a pretty interesting way of doing stuff and I surely can't understand why you do it this way. Here, why not do it like so:

    onready var inventory = self.get_node("inventory")
    
    # first it should be range(0, total_items) or range(1, total_items + 1) otherwise you end up with 1 item less
    for i in range(0, total_items):
        var name = "slot%s" % i
        if not find_node(name):
            var slot = slot_class.new()
            slot.set_name(name)
            self.inventory.add_child(slot) # <- don't use get_node() when you don't have to, store in self.inventory instead, just get it once
    

    Also, you are adding the node to the inventory BEFORE you change the name, you should definitely first change the name then add it to the tree.

  • kyelwkyelw Posts: 6Member

    I apologize as I was trying to clear a lot of the extra parts of the function to keep it easy to read. And it gets iterated over multiple times, which is why it ends up being 1 more than one time. Here's a full function that I've set up
    to test:

    func set_images():
      var inventory = self.get_node("inventory")
      var total_items = 2 # temporarially set to get code working first
    
      for k in range(1,total_items + 1):
      print("item = ",k)
      var name = "slot%s" % k
      print("search = ",name)
      if not find_node(name):
        print("making a new child: slot",k)
        var slot = slot_class.new()
        slot.set_name(name)
        inventory.add_child(slot)
        print("new slot name: ",slot.get_name())
      else:
        print("slot already exists!")
    
     print(" ")
    

    And here's the output. It looks like it still can't find the node, but has a naming conflict.

       ** Debug Process Started **
       item = 1
       search = slot1
       making a new child: slot1
       new slot name: slot1
    
       item = 2
       search = slot2
       making a new child: slot2
       new slot name: slot2
    
       item = 1
       search = slot1
       making a new child: slot1
       new slot name: @slot1@2
    
       item = 2
       search = slot2
       making a new child: slot2
       new slot name: @slot2@3
    
       ** Debug Process Stopped **
    
  • razvanc-rrazvanc-r Posts: 84Member

    Oh, I just read the docs, this is the important bit: Find a descendant of this node whose name matches mask as in String.match (i.e. case sensitive, but ‘*’ matches zero or more characters and ‘?’ matches any single character except ‘.’). Note that it does not match against the full path, just against individual node names.

    So what you want is:

    func set_images():
      var inventory = self.get_node("inventory") # <- also you should just make the inventory a class variable and set it in _ready as I mentioned before (I used `onready`) because if you call `set_images()` multiple times you just `get_node()` multiple times, there's no benefit in that
      var total_items = 2 # temporarially set to get code working first
      for k in range(1,total_items + 1):
      print("item = ",k)
      var name = "slot%s" % k
      print("search = ",name)
      if not inventory.find_node(name): # <- THIS IS THE CHANGE, should work now
        print("making a new child: slot",k)
        var slot = slot_class.new()
        slot.set_name(name)
        inventory.add_child(slot)
        print("new slot name: ",slot.get_name())
      else:
        print("slot already exists!")
     print(" ")
    
  • kyelwkyelw Posts: 6Member

    Hmm... I'm still getting the same thing |:(

    But I did find something interesting:

    This finds a result:

      if not inventory.find_node("slot*"):
    

    because it has an existing child called "slot1_border". And this works:

      if not inventory.find_node("slot?_border"):
    

    But this doesn't work:

      if not inventory.find_node("slot?"):
    

    So it looks like pre-existing children are fine, but dynamically added children aren't.

  • razvanc-rrazvanc-r Posts: 84Member
    Answer ✓

    Oh, my bad. You want to use either:

    1. slot.set_owner(inventory) AFTER inventory.add_child(slot) or
    2. use inventory.find_node(name, true, false) <- true for recrusive, false so it doesn't check owner

    Check http://docs.godotengine.org/en/stable/classes/class_node.html?highlight=set_owner#class-node-set-owner for info on owners

  • kyelwkyelw Posts: 6Member
    edited January 2017

    Hey! That works!

    Interesting, because the way it's worded it looks like it should work without this.
    A) It sounds like it does not need to be recursive as it's looking for just the name of the node. "Note that it does not match against the full path, just against individual node names."
    B ) My assumption was that the listed values were the defaults. "bool recursive=true"

    Now I see that I must be mis-understanding the docs, which makes me feel better.

    Thanks for your help! I really appreciate it!

  • razvanc-rrazvanc-r Posts: 84Member
    Answer ✓

    Just to make it clear. It doesn't have to do with the recursive part, as far as I can tell you're dumping all the nodes under inventory directly. But you have to use find_node(name, SOMETHING(true or false), false) if you want the function to be called with 3 params. That's just the way it is, you can't skip the recursive argument if you want to set the owner parameter. I just set recursive to true because that's the default option. Of course, if you just dump everything under inventory directly you can just as well use find_node(name, false, false) which is a bit faster since it skips some tests. So it's got to do with setting the owner on the node or instructing find_node not to check for owner :).

    Glad it works for you :)

Sign In or Register to comment.