I was experimenting with instantiating scenes through code (object_scene.instantiate()) and placing them, and found that the position for the child scene is (0, 0) for the first physics frame. Here is console output:
From this I could see that the objected is created and set to (152, 40), but it is not acknowledged by the physics_process until the second frame. On the first frame it thinks the position is (0, 0).
In case it was a timing issue, I attempted to wait a frame after setting the position with “await get_tree().process_frame” and also tried a deferred call “obj.set_deferred(“global_position”, Vector2(152, 40))”, but both had the same result. It appears that the first call of _physics_process always thinks the position is (0, 0).
Is this a normal behavior, or a bug? Is there a good fix or workaround? I am currently planning to simply ignore the first physics frame for any instantiated objects that use position in their physics, but I don’t know if this is an issue that could leak into subsequent frames in a more complex project.
Physics is a stepped process and has synchronisation points with the physics_process(), not the frame process().
Whatever you do in-between sync points inside your scripts or SceneTree does not exist as far as the physics space is concerned until the next sync point with physics_process().
Every physics query you make operates on the space data from the last step and sync point.
If the physics object did not exist on the last sync it will either give you an error or a default value. Usually the default is just a zero vector for positions.
Depends on what you are using. Usually you (a)wait the next physics_process() signal or track the physics frame numbers. The sync happens directly before that function is called.
If you create new objects inside the physics_process() function you miss the sync point and need to wait for when the function is called next.
Some nodes do their setup deferred, those will be not ready on the physics_process() after they are created so you need to wait longer. E.g. TileMap or GridMap.
I did find a more satisfying solution. To instantiate the object, I was doing this:
# object_scene is the PackedScene to be created
var obj = object_scene.instantiate()
# parent is the parent node we're adding obj to
parent.add_child(obj)
# pos is a Vector2 for the coordinates where obj should be placed
obj.global_position = to_global(pos)
After some fiddling, I realized I can set the position of obj before adding it to the parent, and it will be recognized immediately by _physics_process:
var obj = object_scene.instantiate()
obj.global_position = to_global(pos)
parent.add_child(obj)
It was unintuitive to me because I didn’t think I could set its position in a scene it wasn’t even added to yet, but it works! This is much preferable since I can avoid having to remember to ignore the first physics_process on every object I might want to instantiate through code.