Unity3d 淺談 Rigidbody + anti-gravity 計算反地心吸力方法.

為了能正確地 hack U3D 的物理環境, 做了點 research, 並且嘗試過不同的方法後總結一下.

把 RigidBody 設 isKinematic / useGravity 是最入門及最基本的 hack.
但很多時候其實我們並不希望完全使用 isKinematic 的方式來移動物件,
而是暫時的依一定的路徑移動, 所以需要的功能如下

  • 違反地心吸力 (anti-gravity)
  • 移動到某個位置 / 進行某種加速度

為了可以真/假物理並存我們必須使用各種不同的辦法.

關於 Anti-gravity

Sample 1)

兩種混合的扺消方式. 達成空中停留的效果.

float m_Duration = 3f;


Rigidbody rb = GetComponent<Rigidbody>();
// A) clear ALL init force
rb.AddForce(-rb.velocity, ForceMode.VelocityChange);

float endTime = Time.timeSinceLevelLoad + m_Duration;
while (Time.timeSinceLevelLoad < endTime)
{
	rb.AddForce(-Physics.gravity, ForceMode.Acceleration); // B) continue anti gravity, but allow to apply any other force.
	yield return new WaitForFixedUpdate();
}
  • (A) 扺消了RB 現在的 velocity, 達到本幀在空中靜止的環境
  • (B) 於每幀的物理運算持績加入完全相反的引力參數,

簡單說如果沒有其他作用力, RB 的重力加速度在時限內會被 (B) 取消, 並保持於零加速度 來達到浮於空中的效果

Sample 2)

使用 Joint, FixedJoint 或者 ConfigableJoint 等, 把 RigidBody 連結在一起.
一般的移動平台也可以使用這種方法. 令物件跟隨平台移動.
為了不影響額外的物理碰撞, 應該盡量避免使用 Break Force = Infinity, 因為這樣會導致玩家可以跑到一些奇怪的地方. (牆裡面的空間, 地圖範圍以外地方…etc)

關於移動

其實很多人直接使用 Rigidbody.velocity 來覆寫加速度是不建議的做法, 也會衍生很多不明顯的問題.
U3D 有提供 MovePosition 跟 MoveRotation 來處理物理移動.

Ref :

最直接及最容易忽略的是 Rigidbody interpolation, 這涉及物理引擎的計算及Update優化,
由於理解可能有錯先附上參考文 :

主要需檢視的問題是

  • Rigidbody 計算是怎樣去計算速度的方法及判斷是否有碰撞 (AABB).
  • 面對 Update, FixedUpdate, 引擎是怎樣判斷物件該繪畫在甚麼地方.

簡單的基本認知是引擎最少每 0.2秒會進行一次的物理運算 (FixedUpdate). 但這個運算時間是浮動的.
而且GPU 在情況許可的情況下會儘可能多地進行 frame 繪畫, 即是 FPS, 一般在 30 及 60 fps 為指標, 這個繪畫時間也是浮動的.

那麼問題就是在一次 FixedUpdate 跟下一次 FixedUpdate 期間, 進行 Update 繪畫時物件存在甚麼地方?!
而我們在處理遊戲時很多時是希望使用引擎本身的物理運算作移動(因為看起來更真實),
但同時也不希望這樣做 (因為我們不希望做用物理計算來 跑樓梯, 或者進行格鬥…)

 

那麼 U3D 提供的 MovePosition 跟 MoveRotation 跟這個有啥關係?

就是當 Interpolation 為開啟狀態時,引擎會依照設定的方式來預判物件的繪畫位置. 最重要的是正確地計算物件在移動時是否有接觸 (AABB)

e.g. 一個 Velocity = 1000000 的火箭從 A 到 B 只需要少於 1 幀的時間. 如果 A 跟 B 點中間有一個 1 unit 的 cube 是否能通過.

以上例子在 interpolation 為 None 時是可以直接通過的. 開啟則可以達到正確的碰撞檢測, 但也較為枆效能.

使用時需注意.

,

發表迴響

你的電子郵件位址並不會被公開。 必要欄位標記為 *

*