為了能正確地 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 :
- https://docs.unity3d.com/ScriptReference/Rigidbody-interpolation.html
- https://docs.unity3d.com/ScriptReference/Rigidbody.MovePosition.html
- https://docs.unity3d.com/ScriptReference/Rigidbody.MoveRotation.html
最直接及最容易忽略的是 Rigidbody interpolation, 這涉及物理引擎的計算及Update優化,
由於理解可能有錯先附上參考文 :
- https://answers.unity.com/questions/767134/physics-what-is-interpolate-extrapolate-discrete-c.html
- http://www.kinematicsoup.com/news/2016/8/9/rrypp5tkubynjwxhxjzd42s3o034o8
主要需檢視的問題是
- 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 時是可以直接通過的. 開啟則可以達到正確的碰撞檢測, 但也較為枆效能.
使用時需注意.