rigid_body.rst 4.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. .. _doc_rigid_body:
  2. Using RigidBody
  3. ===============
  4. What is a rigid body?
  5. ---------------------
  6. A rigid body is one that is directly controlled by the physics engine in order to simulate the behavior of physical objects.
  7. In order to define the shape of the body, it must have one or more :ref:`Shape3D <class_Shape3D>` objects assigned. Note that setting the position of these shapes will affect the body's center of mass.
  8. How to control a rigid body
  9. ---------------------------
  10. A rigid body's behavior can be altered by setting its properties, such as mass and weight.
  11. A physics material needs to be added to the rigid body to adjust its friction and bounce,
  12. and set if it's absorbent and/or rough. These properties can be set in the Inspector or via code.
  13. See :ref:`RigidBody3D <class_RigidBody3D>` and :ref:`PhysicsMaterial <class_PhysicsMaterial>` for
  14. the full list of properties and their effects.
  15. There are several ways to control a rigid body's movement, depending on your desired application.
  16. If you only need to place a rigid body once, for example to set its initial location, you can use the methods provided by the :ref:`Node3D <class_Node3D>` node, such as ``set_global_transform()`` or ``look_at()``. However, these methods cannot be called every frame or the physics engine will not be able to correctly simulate the body's state.
  17. As an example, consider a rigid body that you want to rotate so that it points towards another object. A common mistake when implementing this kind of behavior is to use ``look_at()`` every frame, which breaks the physics simulation. Below, we'll demonstrate how to implement this correctly.
  18. The fact that you can't use ``set_global_transform()`` or ``look_at()`` methods doesn't mean that you can't have full control of a rigid body. Instead, you can control it by using the ``_integrate_forces()`` callback. In this method, you can add *forces*, apply *impulses*, or set the *velocity* in order to achieve any movement you desire.
  19. The "look at" method
  20. --------------------
  21. As described above, using the Node3D's ``look_at()`` method can't be used each frame to follow a target.
  22. Here is a custom ``look_at()`` method called ``look_follow()`` that will work with rigid bodies:
  23. .. tabs::
  24. .. code-tab:: gdscript GDScript
  25. extends RigidBody3D
  26. var speed: float = 0.1
  27. func look_follow(state: PhysicsDirectBodyState3D, current_transform: Transform3D, target_position: Vector3) -> void:
  28. var forward_local_axis: Vector3 = Vector3(1, 0, 0)
  29. var forward_dir: Vector3 = (current_transform.basis * forward_local_axis).normalized()
  30. var target_dir: Vector3 = (target_position - current_transform.origin).normalized()
  31. var local_speed: float = clampf(speed, 0, acos(forward_dir.dot(target_dir)))
  32. if forward_dir.dot(target_dir) > 1e-4:
  33. state.angular_velocity = local_speed * forward_dir.cross(target_dir) / state.step
  34. func _integrate_forces(state):
  35. var target_position = $my_target_node3d_node.global_transform.origin
  36. look_follow(state, global_transform, target_position)
  37. .. code-tab:: csharp
  38. using Godot;
  39. public partial class MyRigidBody3D : RigidBody3D
  40. {
  41. private float _speed = 0.1f;
  42. private void LookFollow(PhysicsDirectBodyState3D state, Transform3D currentTransform, Vector3 targetPosition)
  43. {
  44. Vector3 forwardLocalAxis = new Vector3(1, 0, 0);
  45. Vector3 forwardDir = (currentTransform.Basis * forwardLocalAxis).Normalized();
  46. Vector3 targetDir = (targetPosition - currentTransform.Origin).Normalized();
  47. float localSpeed = Mathf.Clamp(_speed, 0.0f, Mathf.Acos(forwardDir.Dot(targetDir)));
  48. if (forwardDir.Dot(targetDir) > 1e-4)
  49. {
  50. state.AngularVelocity = forwardDir.Cross(targetDir) * localSpeed / state.Step;
  51. }
  52. }
  53. public override void _IntegrateForces(PhysicsDirectBodyState3D state)
  54. {
  55. Vector3 targetPosition = GetNode<Node3D>("MyTargetNode3DNode").GlobalTransform.Origin;
  56. LookFollow(state, GlobalTransform, targetPosition);
  57. }
  58. }
  59. This method uses the rigid body's ``angular_velocity`` property to rotate the body.
  60. The axis to rotate around is given by the cross product between the current forward direction and the direction one wants to look in.
  61. 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,
  62. as the total amount of rotation needed is given by the arccosine of the dot product.
  63. 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,
  64. as discussed in :ref:`doc_using_transforms`.