I am developing a mobile game in Godot 3.5.1 (because the converter to 4 is bad and I don't know how tilemaps now work).
I am developing a dungeon level in which I generate the 2D Terrain using OpenSimplexNoise. Now after that I loop through the empty tiles and spawn an enemy using this function:

func spawn_enemy(x : int,y : int) -> void:
  var enemy := enemy_data.instance()
  get_parent().call_deffered("add_child", enemy)
  enemy.set_deffered("global_position", Vector2(x,y)

Now the problem is the enemy is always spawning at (0,0). I printed the x and y values which I'm passing to the function and they are random and not always (0,0).
Why is this happening ?
What other way can I try to set the position ?
I tried set_global_position() but it gave the same result.
I am frustrated.
Please help.

@Anybody Help is very much appreciated and asked for.

It’s likely because the add child call is deferred as well, and so what is happening is the child is added after the update but not yet initialized (_ready not called yet) and then it sets the position. Then in the next main loop, it initializes the new node (because deferred happens at the end of the prior loop) and this sets it’s position to 0,0.

The way around this is to combine your deferred function calls into a single function and only call that function deferred. In the single function you can call add_child and then set the global position without deferring (since you know the function will be deferred) and that should, I think, fix it because add_child should initialize it right away.

Another option is to set a property/variable on the deferred node you just added and then in the code for the node, check if the property is defined and if it is, move the global position there and set the property to null.

    Although, is there a reason you are doing a deferred call? Removing the deferred parts and just calling the methods directly should also fix the issue.

      TwistedTwigleg So I don't understand completely how to apply your solution.
      I tried:

      func spawn_enemy(enemy,x,y):
        get_parent().add_child(enemy)
        enemy.global_positon = Vector2(x,y)
      
      ...
        enemy = enemy_data.instance()
        call_deffered("spawn_enemy",enemy,x,y)

      This produced the same result

        Bilal yeah, that is more or less what I had in mind… I’m not sure why it didn’t change anything. (Maybe something with add_child has changed since I last used Godot?)

          TwistedTwigleg I think for it to be deferred I need to call it from the enemy. So:

          #in player script
          var enemy := enemy_data.instance()
          enemy.call_deffered("spawn_enemy",x,y)
          #in enemy script
          func spawn_enemy(...
          6 months later

          A sometimes useful way to handle cases like these is to connect to the node's ready or tree_entered signal, and do more of your setup there.

          Your original code...

          func spawn_enemy(x : int,y : int) -> void:
            var enemy := enemy_data.instance()
            get_parent().call_deferred("add_child", enemy)
            enemy.set_deferred("global_position", Vector2(x,y)

          ...could be expressed as:

          func spawn_enemy(x:int, y:int) -> void:
            var enemy := enemy_data.instance()
            get_parent().add_child.call_deferred(enemy)
            enemy.ready.connect(func(): enemy.global_position = Vector2(x,y))

          Note that this will run after the enemy's _ready() function, so if something in there depends on the position, you may run into an issue with this solution - maybe waiting for tree_entered is even more useful (to run before _ready(). Either way, waiting for a signal from the node solves the race-case better than firing two deferred functions.

          Note that the shared code is Godot 4 (GDScript 2), but you can do something similar in Godot 3 as well.