Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AnimatableBody2D doesn't work when parent moves #58269

Open
aXu-AP opened this issue Feb 18, 2022 · 20 comments
Open

AnimatableBody2D doesn't work when parent moves #58269

aXu-AP opened this issue Feb 18, 2022 · 20 comments

Comments

@aXu-AP
Copy link
Contributor

aXu-AP commented Feb 18, 2022

Godot version

v4.0.alpha2.official [79077e6]

System information

Windows 10

Issue description

When animating a moving AnimatableBody2D platform with Path2D, it's physical location doesn't seem to update. Graphically everything seems fine.
Edit: Problem occurs, if AnimatableBody2D's parent moves, ie. node's local transform stays the same, but global transform changes.

Steps to reproduce

Using following setup:
animatablebody

The example project has 2 platforms. The left one is updated with AnimationPlayer, other with Path2DFollow. The left one works as expected, but the right one demonstrates the bug. Just run and see, rigidbody box on the right is floating in the air. Interestingly, collision shape draws in the right place.

Minimal reproduction project

AnimatableBodyTest.zip

@aXu-AP
Copy link
Contributor Author

aXu-AP commented Feb 18, 2022

I tried to figure out what's the problem, and I believe that in physics_body_2d.cpp it subscribes to local transform changing, not global, so moving parent doesn't trigger the update.

I'm not familiar with building and poking the source, so I can't try to fix it, but I hope this is pointing to the right direction :)

@AttackButton
Copy link
Contributor

AttackButton commented Feb 18, 2022

I think this bug is related with: #54915

The workaround for now is to use a remoteTransform.

image

@aXu-AP
Copy link
Contributor Author

aXu-AP commented Feb 18, 2022

I made few more tests and can confirm that this is not directly related to PathFollow2D, but any case, where AnimatableBody's parent is moving. Also, it occurs only for AnimatableBody, other PhysicsBodies work as intended.
Workaround with RemoteTransform works fine.

@aXu-AP aXu-AP changed the title AnimatableBody2D doesn't work with Path2D AnimatableBody2D doesn't work when parent moves Feb 18, 2022
@aXu-AP
Copy link
Contributor Author

aXu-AP commented Jan 31, 2023

I tested this on AnimatableBody3D, and the same issue occurs there as well. Likely the solution to both will be the same, so I won't open a second issue for it.

@JustMog
Copy link

JustMog commented Sep 26, 2023

when using either the remote transform or other workarounds like setting the body's transform to Transform2d.IDENTITY, the body lags behind the parent by a frame, so it's still not a great situation. hoping someone can look into a true fix

@aXu-AP
Copy link
Contributor Author

aXu-AP commented Sep 26, 2023

I tried looking into this again, thinking third time's the charm, but it seems I'm not one step closer to solution.
I thought that since the problem is that physics syncing is performed only on local transforms, it would be enough to move the logic into (global) NOTIFICATION_TRANSFORM_CHANGED notification. However, now AnimatableBodies don't move at all, so clearly I don't understand well enough inner workings of these classes 🤔
It's quite sad that this isn't still working, paths and platforms are so often used together.

@AttackButton
Copy link
Contributor

AttackButton commented Sep 26, 2023

I tried to move to the global transform notification too. All of this seems to be a lot of hacks to make the render sync with the physics. I found a workaround, but not good enough to be merged.

There is no such simple solution for this without something like #76252 or rewriting everything from scratch.

@hawkerm
Copy link

hawkerm commented Oct 2, 2023

Hit this as well, appreciate that there's a workaround, but it's not intuitive at all for figuring out how to make moving platforms or enemies that just go back-and-forth easily with a path.

@SaffronStreams
Copy link

I had trouble using the Path2D> PathFollow2D > RemoteTransform for my setup. The animatablebody always pushed off my player. I switched to just each physics_process updating the position to the position of the Pathfollow for my animatablebody, as I had a feeling somewhere there was something not being updated at physics time. It seemingly worked. If this is correct, perhaps RemoteTransform also needs an "synch with physics" option? (I am hypothesizing without any knowledge of the C side of things)

@YuriSizov YuriSizov modified the milestones: 4.2, 4.x Nov 15, 2023
@ObaniGemini
Copy link

This seems to still happen on 4.2.1 stable

@berarma
Copy link
Contributor

berarma commented Apr 10, 2024

This issue only happens when "sync to physics" is set. My feeling (shared by others in Github) is that "sync to physics" is an ugly hack.

The documentation says this setting is needed when the object is animated from an AnimationPlayer but there's already a callback_mode_process there which can be set to physics. What's the use for it in AnimatableBody2D then?

I think that a better solution would be to sync the originator of the movement instead of the moved object. So the solution could be disabling "sync to physics" and setting callback_mode_process to physics.

I've tried in the test project and it improves significantly the jittering and fixes the collisions, although there's still a 1-pixel gap between the rigid body and the platform. The AnimatableBody2D updated from AnimationPlayer works perfectly so there's must be some other issue creeping here.

So maybe the solution is simply ignoring/removing "sync to physics" here and instead sync the code moving the object.

When using a Tween, setting the process_mode to physics should do it. When updating PathFollow2D directly, doing it from the _physics_process callback should be enough to achieve physics synchronization.

Edit: It seems sync to physics does something after all. It looks like it fixes the gap between the objects by delaying the rendering of the AnimatableBody2D by one frame. I've noticed this in the one updated by AnimationPlayer. This means the physics server is lagging behind the rendering server so any body interaction would need this rendering delay to look in sync. I'm surprised because I would have guessed the physics server would be updated first and the rendering happens after that. But this is maybe another issue.

@berarma
Copy link
Contributor

berarma commented Apr 12, 2024

Ive created a PR that seems to fix this issue although it's as hacky as it already was. It should be better tested to see if it doesn't break anything in some cases.

@leftbones
Copy link

Using RemoteTransform definitely isn't a proper workaround. I have a specific scenario where I need to move the bodies along a path (in a circle) and I need a CharacterBody2D to be able to bounce off of them accurately. In this situation, using RemoteTransform has the exact same problems as just disabling sync to physics.

@Lazy-Rabbit-2001
Copy link

a temporary workaround is the following piece of code:

# in a _*process() method
global_position = global_position

@leftbones
Copy link

a temporary workaround is the following piece of code:

# in a _*process() method
global_position = global_position

What is this supposed to fix? Is this to be used in conjunction with the RemoteTransform, or instead of?

@Lazy-Rabbit-2001
Copy link

a temporary workaround is the following piece of code:

# in a _*process() method
global_position = global_position

What is this supposed to fix? Is this to be used in conjunction with the RemoteTransform, or instead of?

no, but this is used in the script attached to the animated body being a child of the path follower you are using.

@KRC2000
Copy link

KRC2000 commented Sep 3, 2024

Just encountered this issue in 4.3 stable.mono, AnimatableBody3D does not rotate with the parent Node3D.

@40-4
Copy link

40-4 commented Sep 26, 2024

I still seems like thats the case in 4.3 stable. AnimatableBody2D and its collision seems to move (i checked with visible collision shapes on debug), but the real collision doesn't move

Edit: Disabling sync_to_physics seems to fix it, even though it seems counterintuitive (and feels wrong?)

@aniezurawski
Copy link

aniezurawski commented Oct 10, 2024

Edit: It seems sync to physics does something after all. It looks like it fixes the gap between the objects by delaying the rendering of the AnimatableBody2D by one frame. I've noticed this in the one updated by AnimationPlayer. This means the physics server is lagging behind the rendering server so any body interaction would need this rendering delay to look in sync. I'm surprised because I would have guessed the physics server would be updated first and the rendering happens after that. But this is maybe another issue.

@berarma I encountered this issue myself and after some testing, digging into the code and asking around on forum about what is the actual idea behind sync to physics I have new hypothesis.
I am not sure about its correctness but I think that the idea here is that it's impossible to predict next position of the platform in a general case. There would be no issue if the platform moved in uniform, uniformly accelerated, or any other predictable motion. But it's not possible to perfectly predict it's next position in general case. So to solve it AnimatedBody2D is (by design) delayed by a single frame so we can use what was supposed to be its current position as a perfect prediction of its future position. Now when checking for collisions we exactly know where to put player character to eliminate any jittering completely because, though in _process_physics() we only have access to previous state of PhysicsServer, there is actually a future position of delayed platform.

Hypothetically this could be solved another way - by running another round of adjustments for some specific objects in the same physics frame. So we could stick character to the platform if we miscalculated its future position by small margin in first iteration. But it would be much complicated because we would have to actually care about predicting next position of platform, be ready for mistakes and additional adjustments. With sync to physics we have the delay by a frame but with no additional cost it works for any nature of movement - no matter how complicated.

@berarma
Copy link
Contributor

berarma commented Oct 11, 2024

@berarma I encountered this issue myself and after some testing, digging into the code and asking around on forum about what is the actual idea behind sync to physics I have new hypothesis. I am not sure about its correctness but I think that the idea here is that it's impossible to predict next position of the platform in a general case. There would be no issue if the platform moved in uniform, uniformly accelerated, or any other predictable motion. But it's not possible to perfectly predict it's next position in general case. So to solve it AnimatedBody2D is (by design) delayed by a single frame so we can use what was supposed to be its current position as a perfect prediction of its future position. Now when checking for collisions we exactly know where to put player character to eliminate any jittering completely because, though in _process_physics() we only have access to previous state of PhysicsServer, there is actually a future position of delayed platform.

Hypothetically this could be solved another way - by running another round of adjustments for some specific objects in the same physics frame. So we could stick character to the platform if we miscalculated its future position by small margin in first iteration. But it would be much complicated because we would have to actually care about predicting next position of platform, be ready for mistakes and additional adjustments. With sync to physics we have the delay by a frame but with no additional cost it works for any nature of movement - no matter how complicated.

There's two points here:

  • The quirkiness of the physics server needing the future position of an object. It should be enough with having all past positions. And I think the issue might be that AnimatableBody2D physics updates happen late in the physics frame, after move_and_slide calls have been processed. Anyway, since I guess this requirement would be hard to change delaying the rendering by one frame is an acceptable solution in most cases.

  • And the real problem being that the way this workaround is implemented not only delays the rendering in the screen, it also detaches the physics object from the rendered object when the parent moves.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests