What `sync_to_physics` actually does?

Godot Version

4.3

Question

Since nobody was able to help me in my last topic I trying to dig deeper to understand source of my issues. So I want to understand what sync_to_physics does. Not what it is meant to be used for, but what it really does under the hood. I tried to read the source code but it was hard to get anything out of it without any context.

Docs says this about sync_to_physics:

If true, the body’s movement will be synchronized to the physics frame. This is useful when animating movement via AnimationPlayer, for example on moving platforms.

So what I can get from this and some testing is that it magically “fixes” moving platforms. But it does not really explain how it achieve it. And moreover it does it at great cost of making platform be delayed by a frame leading to some other potential issues.
Here’s my origin issue for more context: AnimatableBody2D moved by RemoteTransform2D out of sync - #2 by Wajsia

Well, this is kinda an explanation:

If true, the body’s movement will be synchronized to the physics frame.

So I want to understand what this sentence really means. Because I don’t.

How anything can be not “synchronized to the physics frame” at first place if my game is single-threaded? My current understanding is that in single-threaded games with both - FPS and physics ticks per second set to be equal 60, the main game loop should be more or less equivalent to this:

while (true) {
    _physics_process(delta)
    // Not relevant for games without Rigid Bodies
    // _integrate_forces()
    // _PhysicsEngine2D.run_tick()
    _process(delta)
    render_frame()
}

So where is the place for anything being out of sync and what sync_to_physics changes in the way how AnimatableBody2D works in this loop? How is that that sync_to_physics make body delayed but also make it work at all in such a straightforward game loop? I does something very important because without it a player character can even easily penetrate through platforms which is not the case when sync_to_physics is set to true.

I feel like I’m missing something very fundamental.

I find it a drawback of Godot that the docs quite often don’t go into to much details and just tells you for what you are supposed to use something instead of explaining what it actually does. It makes it a little less friendly for advanced usage.

There’s also this in docs:

Do not use together with PhysicsBody2D.move_and_collide.

Would be nice to say few works why. Does this rule still apply if you use move_and_collide with test_only=true?

3 Likes

check this out, if you enable sync_to_physics, then the animation player’s set wont work, so you have to disable it for it to work

which exactly what this say

This is useful when animating movement via AnimationPlayer, for example on moving platforms.

What that AnimatableBody.sync_to_physics does is:

  1. Node transform gets changed by anything.
  2. Node transform gets send to PhysicsServer for body update.
  3. Node transform gets reset to the previous transform, canceling the transform change for the SceneTree but not for the PhysicsServer.
  4. Node transform waits for the actual physics body callback done by the server to update node transform.

So bascially an AnimatableBody2D/3D will reject any transform change to its Node done by anything at first. Does not matter if it is a script or AnimationPlayer or some other node like RemoteTransform trying to change the transform, it will always be reverted immediately.

Instead what the AnimatableBody does with the transform change attempt is to send the new resulting transform to the PhysicsServer for a body update. Only after the PhysicsServer has done its physics calculation for the current step with this new body transform will the Node transform be updated with the result.

1 Like

Thanks. Good explanation. But I still want to dig into some details.

So one thing that I got wrong at first place is that tick of PhysicsEngine2D is irrelevant for games without RigidBodies. It is relevant and actually do some job in this case - it sends back transformation to AnimatableBody2D. Do I get it right?

If that is so then it still happens before _process and before frame is rendered so why does platform appear to be a frame behind? We are talking here only in context of single-threaded games.

Physics is a stepped process that is not necessarily in sync with your frame rate.

You will have multiple rendered frames with zero physics steps done and frames with x-amount of them.

The synchronisation for physics happens after all the changes from SceneTree physics nodes and user physics_process() input is done. Everything that is not controlled by physics directly (e.g. rigidy body) does its calculation on the space data from the last sync.

Physics is a stepped process that is not necessarily in sync with your frame rate.

Is this true even for single-threaded game with FPS equals exactly to physics ticks per second? It seems like it should be in sync in that case. From docs:

The function _process() is not synchronized with physics. Its rate depends on hardware and game optimization. It also runs after the physics step in single-threaded games.

It seems to suggest that in single threaded games rendering it will be in sync. But it may actually be completely irrelevant to my issues. Since my moving platform is a frame behind all other objects in the world (including the one it’s following via RemoteTransform2D) it doesn’t matter when it all is rendered. It may be not rendered at all and still be out of sync in sense of game logic.

Also additional question to this part:

Node transform gets reset to the previous transform, canceling the transform change for the SceneTree but not for the PhysicsServer.

Does it actually cancel the change in the way that if any other Node (with lower priority) will access this node’s position in _physics_process it will read an old value or is this some kind of “internal” cancellation of engine? When exactly this cancellation happens? Is it instant like a setter of a variable just refuse to store new value and send some signal instead?

And how actually all these things make moving platforms “work correctly” (like in - not let character penetrate the platform)? Since you said that

Everything (…) does its calculation on the space data from the last sync.

How putting this transformation on hold makes any difference? Every other node will see previous state of physics engine anyway.

Threading has nothing to do with any of this. The mainloop and sync points are never threaded.

The SceneTree and all Nodes are also inherently single-threaded by nature.

What runs on threads if enabled are background tasks or tasks that can be split into multiple batches that each can be solved by a thread to speed things up. E.g. solving physics or avoidance constrains or rendering culls. All those threads still need to be joined together at the sync points.

All the Animateable Body does is set the last_valid_transform on the Node, same as you would call set_global_transform() yourself.

That last_valid_transform is the transform that is set when the Node joins the SceneTree or when it receives the PhysicsServer callback in which case it updates it to the transform of the body.

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.