使用 RigidBody

什麼是剛體?

剛體是由物理引擎直接控制,以模擬實際物件行為的物件。為了定義剛體的形狀,必須指派一個或多個 Shape3D 物件。請注意,設定這些形狀的位置會影響剛體的質心。

如何控制剛體

剛體的行為可以透過設定其屬性來調整,例如質量和重量。你需要為剛體新增物理材質,以調整其摩擦力和彈力,並設定其是否具備吸收性或粗糙度。這些屬性可以在屬性檢查器中設定,或是透過程式碼調整。完整屬性列表及其效果,請參考 RigidBody3DPhysicsMaterial

依照你的需求,有多種方式可以控制剛體的移動。

如果你只需要設定剛體一次,例如設定其初始位置,可以使用 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)

這個方法會利用剛體的 angular_velocity 屬性來旋轉剛體。旋轉軸是由當前前方方向與目標方向的向量叉積所決定。clamp 則用來避免旋轉量超過所需的目標方向,因為實際所需的旋轉量是由兩向量的點積再取反餘弦得出。這個方法也可以搭配 axis_lock_angular_* 屬性一起使用。如果需要更精確的控制,可能需要依賴 Quaternion 等方案,如 使用 3D 變換 所討論。