godotengine / godot-docs

Godot Engine official documentation
https://docs.godotengine.org
Other
3.94k stars 3.22k forks source link

Clarify Rigid Body physics caveats #10228

Open ScottFreeCode opened 1 week ago

ScottFreeCode commented 1 week ago

Your Godot version:

4.3 (docs)

Issue description:

The warnings around adjusting the velocity or position of a rigid body and around the use of _integrate_forces, are somewhat inconsistent and are unclear on some of the exact details.

URL to the documentation page (if already existing):

https://docs.godotengine.org/en/stable/tutorials/physics/rigid_body.html says merely that you shouldn't set position or rotation every frame outside the _integrate_forces callback, and gives an example of using that callback to control rotation, leaving open (if I didn't miss something) the possibility of applying forces elsewhere.

But https://docs.godotengine.org/en/stable/tutorials/physics/physics_introduction.html#rigidbody2d first says that setting position or velocity can have "unexpected" results, then says to prefer using _integrate_forces to synchronize that kind of state, then gives an example of _integrate_forces that does not set position or velocity, then explicitly calls out that it is only applying force and torque. This leaves the reader with the impression that one should only ever apply forces and only in the _integrate_forces callback.

https://docs.godotengine.org/en/stable/classes/class_rigidbody2d.html even vaguely says that "unexpected behavior" can happen if you set the transform or velocity outside _integrate_forces "very often", which leaves one wondering if it's fine as long as it's "not too often" and how often is often enough to cause problems.

Specific clarifying questions

The docs could spell out the answers to these, or the answers could be used to improve the docs above.

Rotation (& translation) in examples

The examples in https://docs.godotengine.org/en/stable/tutorials/physics/physics_introduction.html#rigidbody2d and https://docs.godotengine.org/en/stable/tutorials/physics/rigid_body.html don't actually set rotation or position.

They could, with state.transform = state.transform.rotated(amount) (or .translated(vector)), but they don't.

One is merely applying force and torque, which leaves it ambiguous whether the rule is "you cannot adjust position or velocity only apply forces, and you cannot even apply forces outside this special callback" vs "you can apply force and torque, or adjust anything in this special callback, but cannot directly adjust position or velocity outside this special callback." The other is trying to synchronize a rotation by adjusting angular velocity, which admittedly the docs say velocity changes shouldn't be done outside _integrate_forces either, but it's relatively indirect and complex compared to setting the rotation.

Assuming it's safe to adjust position and rotation on the transform on the state in _integrate_forces, it would be good to clarify with a confirmation and example of doing so.

Step

One advantage of the current example setting angular velocity, is that it uses the state's step for the calculation.

It might be worth calling out that, while you don't need the delta if you apply forces since the physics engine calculates it, if and when your calculations need the delta they can still get it as the state's step property (since the state parameter replaces the delta parameter).

Applying force at different levels

Both the RigidBody2D and the state passed to _integrate_forces have methods to apply force, torque etc. Furthermore, a glance at the implementation of the force methods for RigidBody suggests they do not update velocity or position, merely add to a force variable to be used in the next physics calculation. Nonetheless the examples make it sound as though you should be using _integrate_forces with its state object to apply forces.

What is the difference between applying force outside _physics_process and _integrate_forces, applying force in _physics_process, applying it with the node's methods in _integrate_forces, and applying it with the state's methods in _integrate_forces?

Impulse

The documentation for the impulse functions on RigidBody2D says they should not be applied every frame. A glance at the implementation suggests they add to the velocity. The documentation for rigid bodies suggests you shouldn't do that except in _integrate_forces, which is applied every frame.

Is it actually safe to add to position (i.e. translate) or velocity (e.g. apply impulse) outside _integrate_forces as long as it's not done every frame?

Overriding position outside _integrate_forces

https://docs.godotengine.org/en/stable/tutorials/physics/rigid_body.html says that you can set the transform, say, one time initially, but should use _integrate_forces instead of adjustments every frame because those would prevent the physics calculation from working.

Would I be correct in inferring that if you set position or velocity outside _integrate_forces then it will take effect regardless of the physics engine's calculations? That is, the physics engine won't overwrite your code's action?

Would this make it safe to, for example, set position when switching scenes and transferring a rigid body from the previous scene into the new one? Or to create an effect like Super Mario 64's "infinite staircase" where the player is instantly translated when they enter a certain hitbox/field (such as an Area2D)?

If the above ideas are not safe, could we get an example of how to safely implement a translation that needs to occur when some other event has happened (e.g. a signal on another node)?

One small code example improvement

By the way, the example on https://docs.godotengine.org/en/stable/tutorials/physics/physics_introduction.html#rigidbody2d has an else branch that applies an empty force, which could be deleted from the example code.

TL;DR

I suspect that the only thing you shouldn't do is:

…and that it is fine, provided the resulting behavior is what you want, to:

If so, the documentation could be clarified on any or all of those points.

ScottFreeCode commented 1 week ago

Corrected a few typos, some subtle but important. If you're reading email notifications, here's the updated bits:

"Document URLs" section, physics introduction RigidBody2D description:

then gives an example of _integrate_forces that does not set position or velocity

"Rotation (& translation) in examples":

Assuming it's safe to adjust position and rotation on the transform on the state in _integrate_forces, it would be good to clarify with a confirmation and example of doing so.

"Step" (subsection in previous section):

if and when your calculations need the delta