使用 RigidBody

什么是刚体?

刚体是由物理引擎直接控制的物体,用于模拟物体的的物理行为。为了定义刚体的形状,必须为其指定一个或多个 Shape3D 对象。注意,设置这些形状的位置将影响物体的质心。

如何控制刚体

刚体的行为可以通过设置其属性(例如质量和重量)来进行调整。需要给刚体添加一个物理材质来调整它的摩擦和反弹,并设置它是否具有吸收性、粗糙度。这些属性可以在检查器中或通过代码来设置。参见 RigidBody3DPhysicsMaterial 获取完整的属性列表和它们的效果。

有几种方法可以控制刚体的运动, 这取决于你的应用程序.

如果你只需要放置一次刚体,例如设置它的初始位置,你可以使用 Node3D 节点提供的方法,例如 set_global_transform()look_at() 。但是,这些方法不能每一帧都被调用,否则物理引擎将无法正确地仿真物体的状态。举个例子,考虑一个刚体,你想旋转它,使它指向另一个对象。在实现这种行为时,一个常见的错误是每一帧都使用 look_at() ,这样会破坏物理仿真。下面,我们将演示如何正确地实现这一点。

你不能使用 set_global_transform()look_at() 方法并不意味着你不能完全控制一个刚体. 相反, 你可以通过使用 _integrate_forces() 回调来控制它. 在这个方法中, 你可以添加 , 应用 冲量 , 或者设置 速度 , 以实现你想要的任何运动.

“look at”方法

如上所述,使用 Node3D 节点的 look_at() 方法不能每一帧都用来跟踪一个目标。这里有一个自定义的 look_at() 方法叫做 look_follow() ,可以适用于刚体:

GDScriptC#

  1. extends RigidBody3D
  2. var speed: float = 0.1
  3. func look_follow(state: PhysicsDirectBodyState3D, current_transform: Transform3D, target_position: Vector3) -> void:
  4. var forward_local_axis: Vector3 = Vector3(1, 0, 0)
  5. var forward_dir: Vector3 = (current_transform.basis * forward_local_axis).normalized()
  6. var target_dir: Vector3 = (target_position - current_transform.origin).normalized()
  7. var local_speed: float = clampf(speed, 0, acos(forward_dir.dot(target_dir)))
  8. if forward_dir.dot(target_dir) > 1e-4:
  9. state.angular_velocity = local_speed * forward_dir.cross(target_dir) / state.step
  10. func _integrate_forces(state):
  11. var target_position = $my_target_node3d_node.global_transform.origin
  12. look_follow(state, global_transform, target_position)
  1. using Godot;
  2. public partial class MyRigidBody3D : RigidBody3D
  3. {
  4. private float _speed = 0.1f;
  5. private void LookFollow(PhysicsDirectBodyState3D state, Transform3D currentTransform, Vector3 targetPosition)
  6. {
  7. Vector3 forwardLocalAxis = new Vector3(1, 0, 0);
  8. Vector3 forwardDir = (currentTransform.Basis * forwardLocalAxis).Normalized();
  9. Vector3 targetDir = (targetPosition - currentTransform.Origin).Normalized();
  10. float localSpeed = Mathf.Clamp(_speed, 0.0f, Mathf.Acos(forwardDir.Dot(targetDir)));
  11. if (forwardDir.Dot(targetDir) > 1e-4)
  12. {
  13. state.AngularVelocity = forwardDir.Cross(targetDir) * localSpeed / state.Step;
  14. }
  15. }
  16. public override void _IntegrateForces(PhysicsDirectBodyState3D state)
  17. {
  18. Vector3 targetPosition = GetNode<Node3D>("MyTargetNode3DNode").GlobalTransform.Origin;
  19. LookFollow(state, GlobalTransform, targetPosition);
  20. }
  21. }

该方法使用刚体的 angular_velocity 特性来旋转刚体。要绕其旋转的轴是由当前正向方向和想要观察的方向之间的叉积给出的。 clamp 是一种简单的方法,用于防止旋转量超过想要查看的方向,因为所需的旋转总量是由点积的反余弦给出的。此方法也可以与 axis_lock_angular_* 一起使用。如果需要更精确的控制,则可能需要依赖于 Quaternion 的解决方案,如 使用 3D 变换