Open ScottFreeCode opened 1 week ago
Corrected a few typos, some subtle but important. If you're reading email notifications, here's the updated bits:
then gives an example of
_integrate_forces
that does not set position or velocity
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.
if and when your calculations need the delta
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:
_integrate_forces
…and that it is fine, provided the resulting behavior is what you want, to:
_integrate_forces
you should do it on the state not the node to avoid a one tick delay or something)_integrate_forces
If so, the documentation could be clarified on any or all of those points.