Attention: Here be dragons
This is the latest
(unstable) version of this documentation, which may document features
not available in or compatible with released stable versions of Godot.
Checking the stable version of the documentation...
使用 RigidBody
什麼是剛體?
剛體是由物理引擎直接控制,以模擬實際物件行為的物件。為了定義剛體的形狀,必須指派一個或多個 Shape3D 物件。請注意,設定這些形狀的位置會影響剛體的質心。
如何控制剛體
剛體的行為可以透過設定其屬性來調整,例如質量和重量。你需要為剛體新增物理材質,以調整其摩擦力和彈力,並設定其是否具備吸收性或粗糙度。這些屬性可以在屬性檢查器中設定,或是透過程式碼調整。完整屬性列表及其效果,請參考 RigidBody3D 與 PhysicsMaterial 。
依照你的需求,有多種方式可以控制剛體的移動。
如果你只需要設定剛體一次,例如設定其初始位置,可以使用 Node3D 節點所提供的方法,例如 set_global_transform() 或 look_at()。但這些方法不能在每一幀都呼叫,否則物理引擎將無法正確模擬剛體的狀態。舉例來說,假設你想讓一個剛體旋轉並指向另一個物件,一個常見錯誤是每幀都使用 look_at(),這會破壞物理模擬。以下我們會示範正確的實作方式。
無法使用 set_global_transform() 或 look_at() 方法並不代表你就不能完全控制剛體。你可以透過 _integrate_forces() 回呼函式來控制剛體。在這個方法中,你可以加上*力*、施加*衝量*,或設定*速度*,來達到你想要的任何移動效果。
「look at」方法
如上所述,使用 Node3D 的 look_at() 方法不能在每一幀用來追蹤目標。這裡提供一個自訂的 look_follow() 方法,適用於剛體:
extends RigidBody3D
var speed: float = 0.1
func look_follow(state: PhysicsDirectBodyState3D, current_transform: Transform3D, target_position: Vector3) -> void:
var forward_local_axis: Vector3 = Vector3(1, 0, 0)
var forward_dir: Vector3 = (current_transform.basis * forward_local_axis).normalized()
var target_dir: Vector3 = (target_position - current_transform.origin).normalized()
var local_speed: float = clampf(speed, 0, acos(forward_dir.dot(target_dir)))
if forward_dir.dot(target_dir) > 1e-4:
state.angular_velocity = local_speed * forward_dir.cross(target_dir) / state.step
func _integrate_forces(state):
var target_position = $my_target_node3d_node.global_transform.origin
look_follow(state, global_transform, target_position)
using Godot;
public partial class MyRigidBody3D : RigidBody3D
{
private float _speed = 0.1f;
private void LookFollow(PhysicsDirectBodyState3D state, Transform3D currentTransform, Vector3 targetPosition)
{
Vector3 forwardLocalAxis = new Vector3(1, 0, 0);
Vector3 forwardDir = (currentTransform.Basis * forwardLocalAxis).Normalized();
Vector3 targetDir = (targetPosition - currentTransform.Origin).Normalized();
float localSpeed = Mathf.Clamp(_speed, 0.0f, Mathf.Acos(forwardDir.Dot(targetDir)));
if (forwardDir.Dot(targetDir) > 1e-4)
{
state.AngularVelocity = forwardDir.Cross(targetDir) * localSpeed / state.Step;
}
}
public override void _IntegrateForces(PhysicsDirectBodyState3D state)
{
Vector3 targetPosition = GetNode<Node3D>("MyTargetNode3DNode").GlobalTransform.Origin;
LookFollow(state, GlobalTransform, targetPosition);
}
}
這個方法會利用剛體的 angular_velocity 屬性來旋轉剛體。旋轉軸是由當前前方方向與目標方向的向量叉積所決定。clamp 則用來避免旋轉量超過所需的目標方向,因為實際所需的旋轉量是由兩向量的點積再取反餘弦得出。這個方法也可以搭配 axis_lock_angular_* 屬性一起使用。如果需要更精確的控制,可能需要依賴 Quaternion 等方案,如 使用 3D 變換 所討論。