Skip to content

Commit d1edd1c

Browse files
authored
Merge pull request #8179 from golfinq/rigidbody-workaround-fix
Fixed code in article "Using RigidBody"
2 parents 4ff7893 + 3bca95a commit d1edd1c

File tree

1 file changed

+29
-21
lines changed

1 file changed

+29
-21
lines changed

tutorials/physics/rigid_body.rst

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -29,21 +29,23 @@ The "look at" method
2929
--------------------
3030

3131
As described above, using the Node3D's ``look_at()`` method can't be used each frame to follow a target.
32-
Here is a custom ``look_at()`` method that will work reliably with rigid bodies:
32+
Here is a custom ``look_at()`` method called ``look_follow()`` that will work with rigid bodies:
3333

3434
.. tabs::
3535
.. code-tab:: gdscript GDScript
3636

3737
extends RigidBody3D
3838

39-
func look_follow(state, current_transform, target_position):
40-
var up_dir = Vector3(0, 1, 0)
41-
var cur_dir = current_transform.basis * Vector3(0, 0, 1)
42-
var target_dir = current_transform.origin.direction_to(target_position)
43-
var rotation_angle = acos(cur_dir.x) - acos(target_dir.x)
44-
45-
state.angular_velocity = up_dir * (rotation_angle / state.step)
39+
var speed: float = 0.1
4640

41+
func look_follow(state: PhysicsDirectBodyState3D, current_transform: Transform3D, target_position: Vector3) -> void:
42+
var forward_local_axis: Vector3 = Vector3(1, 0, 0)
43+
var forward_dir: Vector3 = (current_transform.basis * forward_local_axis).normalized()
44+
var target_dir: Vector3 = (target_position - current_transform.origin).normalized()
45+
var local_speed: float = clampf(speed, 0, acos(forward_dir.dot(target_dir)))
46+
if forward_dir.dot(target_dir) > 1e-4:
47+
state.angular_velocity = local_speed * forward_dir.cross(target_dir) / state.step
48+
4749
func _integrate_forces(state):
4850
var target_position = $my_target_node3d_node.global_transform.origin
4951
look_follow(state, global_transform, target_position)
@@ -54,24 +56,30 @@ Here is a custom ``look_at()`` method that will work reliably with rigid bodies:
5456

5557
public partial class MyRigidBody3D : RigidBody3D
5658
{
57-
private void LookFollow(PhysicsDirectBodyState state, Transform3D currentTransform, Vector3 targetPosition)
59+
private float _speed = 0.1f;
60+
private void LookFollow(PhysicsDirectBodyState3D state, Transform3D currentTransform, Vector3 targetPosition)
5861
{
59-
var upDir = new Vector3(0, 1, 0);
60-
var curDir = currentTransform.Basis * new Vector3(0, 0, 1);
61-
var targetDir = currentTransform.Origin.DirectionTo(targetPosition);
62-
var rotationAngle = Mathf.Acos(curDir.X) - Mathf.Acos(targetDir.X);
63-
64-
state.SetAngularVelocity(upDir * (rotationAngle / state.GetStep()));
62+
Vector3 forwardLocalAxis = new Vector3(1, 0, 0);
63+
Vector3 forwardDir = (currentTransform.Basis * forwardLocalAxis).Normalized();
64+
Vector3 targetDir = (targetPosition - currentTransform.Origin).Normalized();
65+
float localSpeed = Mathf.Clamp(_speed, 0.0f, Mathf.Acos(forwardDir.Dot(targetDir)));
66+
if (forwardDir.Dot(targetDir) > 1e-4)
67+
{
68+
state.AngularVelocity = forwardDir.Cross(targetDir) * localSpeed / state.Step;
69+
}
6570
}
6671

67-
public override void _IntegrateForces(PhysicsDirectBodyState state)
72+
public override void _IntegrateForces(PhysicsDirectBodyState3D state)
6873
{
69-
var targetPosition = GetNode<Node3D>("MyTargetNode3DNode").GetGlobalTransform().Origin;
70-
LookFollow(state, GetGlobalTransform(), targetPosition);
74+
Vector3 targetPosition = GetNode<Node3D>("MyTargetNode3DNode").GlobalTransform.Origin;
75+
LookFollow(state, GlobalTransform, targetPosition);
7176
}
7277
}
7378

7479

75-
This method uses the rigid body's ``angular_velocity`` property to rotate the body. It first calculates the difference between the current and desired angle and then adds the velocity needed to rotate by that amount in one frame's time.
76-
77-
.. note:: This script will not work with rigid bodies in *character mode* because then, the body's rotation is locked. In that case, you would have to rotate the attached mesh node instead using the standard Node3D methods.
80+
This method uses the rigid body's ``angular_velocity`` property to rotate the body.
81+
The axis to rotate around is given by the cross product between the current forward direction and the direction one wants to look in.
82+
The ``clamp`` is a simple method used to prevent the amount of rotation from going past the direction which is wanted to be looked in,
83+
as the total amount of rotation needed is given by the arccosine of the dot product.
84+
This method can be used with ``axis_lock_angular_*`` as well. If more precise control is needed, solutions such as ones relying on :ref:`class_Quaternion` may be required,
85+
as discussed in :ref:`doc_using_transforms`.

0 commit comments

Comments
 (0)