Unity 物理系列一 剛體 碰撞體

參考
Cocos 3.x 3D物理系統(tǒng) 射線檢測
[專欄精選]Unity剛體詳解

一、RigidBody

https://docs.unity.cn/cn/2019.4/Manual/class-Rigidbody.html

Cocos 3.x中的RigidBody概念上與Unity是一致的,但是稍有區(qū)別:


image.png
1.剛體類型

動態(tài) Dynamic

  • 默認類型
  • 受重力和附加力的影響,進而改變速度。
  • 性能消耗最高的類型。
  • 可通過 MovePosition、MoveRotation 來移動。
  • 可通過 velocity 來改變速度。
  • 用來模擬移動的物體。

運動學 Kinematic

  • 不受力的影響。
  • 性能消耗比 Dynamic 少,比 Static 多。
  • 可通過 MovePosition MoveRotation 來移動。
  • 可通過 velocity 來改變速度。
  • 用來模擬大多數(shù)時候不動的物體,極少數(shù)時候需要移動。比如門。

靜態(tài) Static

  • 不受力的影響,物理系統(tǒng)不會對該物體進行計算。
  • 性能消耗最低的類型。
  • 不可通過 MovePosition MoveRotation 來移動。
  • 不可通過 velocity 來改變速度。
  • 用來模擬從不移動的物體。

cocos通過type選擇剛體類型,unity中是這樣的:
參考https://docs.unity.cn/cn/2019.4/Manual/CollidersOverview.html

  • 可將碰撞體添加到?jīng)]有剛體組件的游戲?qū)ο?,從而?chuàng)建場景的地板、墻壁和其他靜止元素。這些被稱為靜態(tài)碰撞體。
  • 相反,具有剛體的游戲?qū)ο笊系呐鲎搀w稱為動態(tài)碰撞體。靜態(tài)碰撞體可與動態(tài)碰撞體相互作用,但由于沒有剛體,因此不會通過移動來響應碰撞。

參考https://docs.unity.cn/cn/2019.4/Manual/RigidbodiesOverview.html

剛體 (Rigidbody)是實現(xiàn)游戲?qū)ο蟮奈锢硇袨榈闹饕M件。連接剛體后,對象將立即響應重力。如果還添加了一個或多個碰撞體組件,則游戲?qū)ο髸虬l(fā)生碰撞而移動。

由于剛體組件會接管附加到的游戲?qū)ο蟮倪\動,因此不應試圖借助腳本通過更改變換屬性(如位置和旋轉)來移動游戲?qū)ο?。相反,應該施加力來推動游戲?qū)ο蟛⒆屛锢硪嬗嬎憬Y果。

在某些情況下,可能希望游戲?qū)ο缶哂袆傮w,并讓剛體的運動擺脫物理引擎的控制。例如,可能希望直接從腳本代碼控制角色,但仍允許觸發(fā)器檢測角色。腳本產(chǎn)生的這種非物理運動稱為運動學運動。剛體組件有一個名為 Is Kinematic 的屬性,該屬性可以讓剛體擺脫物理引擎的控制,并允許通過腳本以運動學方式來移動剛體。可以通過腳本來更改 Is Kinematic 的值,從而為某個對象開啟和關閉物理引擎,但這會產(chǎn)生性能開銷,應謹慎使用。

可將碰撞體添加到?jīng)]有剛體組件的游戲?qū)ο螅瑥亩鴦?chuàng)建場景的地板、墻壁和其他靜止元素。這些被稱為靜態(tài)碰撞體。相反,具有剛體的游戲?qū)ο笊系呐鲎搀w稱為動態(tài)碰撞體。靜態(tài)碰撞體可與動態(tài)碰撞體相互作用,但由于沒有剛體,因此不會通過移動來響應碰撞。

場景里有一些物體是基本不會動的,比如說一棟大樓,一塊大石頭等等,他們只需要阻擋別的物體別穿過他們就行了,所以它們只需要添加Collider就行。因為添加了Rigidbody組件后會帶來很多的物理計算,所以只需要給會移動的物體添加Rigidbody就行

2.屬性
  • Mass 對象的質(zhì)量(默認為千克)。
  • Drag 根據(jù)力移動對象時影響對象的空氣阻力大小。0 表示沒有空氣阻力,無窮大使對象立即停止移動。
  • Angular Drag 根據(jù)扭矩旋轉對象時影響對象的空氣阻力大小。0 表示沒有空氣阻力。請注意,如果直接將對象的 Angular Drag 屬性設置為無窮大,無法使對象停止旋轉。
  • Use Gravity 如果啟用此屬性,則對象將受重力影響。
  • Is Kinematic 如果啟用此選項,則對象將不會被物理引擎驅(qū)動,只能通過變換 (Transform)對其進行操作。

Drag和Angular Drag與Cocos 3.x中的Linear Damping 、Angular Damping 是一樣的。

3.Interpolate 如果發(fā)現(xiàn)剛體移動有卡頓,可以嘗試選擇此選項
  • None 不應用插值。
  • Interpolate 根據(jù)前一幀的變換來平滑變換。
  • Extrapolate 根據(jù)下一幀的估計變換來平滑變換。

默認情況下,插值是關閉的。通常對玩家的角色使用剛體插值。 物理以離散時間步長運行,而圖形以可變幀率渲染。 由于物理和圖形并不完全同步,這可能導致對象出現(xiàn)視覺抖動。 這種效果很細微,但通常能夠在玩家角色上看到,特別是當攝像機跟隨主角時。 建議對主角打開插值,對于其他所有內(nèi)容,則禁用它。

4.Collision Detection 用于防止快速移動的對象穿過其他對象而不檢測碰撞。

連續(xù)碰撞檢測是一種阻止快速移動的碰撞體相互穿過的功能。使用正常 (Discrete) 碰撞檢測時,如果對象在一個幀中位于某個碰撞體的一側,而在下一幀中已經(jīng)穿過了碰撞體,便屬于彼此穿過的情況。要解決此問題,可在快速移動對象的剛體上啟用連續(xù)碰撞檢測。

將碰撞檢測模式設置為 Continuous 可防止剛體穿過任何靜態(tài)(即非剛體)網(wǎng)格碰撞體。設置為 Continuous Dynamic 也會防止剛體穿過任何其他支持的剛體(即,碰撞檢測模式設置為 Continuous 或 Continuous Dynamic 的剛體)。 盒型碰撞體、球形碰撞體和膠囊碰撞體支持連續(xù)碰撞檢測。請注意,連續(xù)碰撞檢測的目的是作為一種安全機制,可在對象會相互穿過的情況下捕獲碰撞,但不會提供精確物理碰撞的結果;所以如果遇到快速移動對象的問題,仍然可以考慮在 TimeManager 檢視面板中降低固定時間步長值以使模擬更準確。

  • Discrete 對場景中的所有其他碰撞體使用離散碰撞檢測。其他碰撞體在測試碰撞時會使用離散碰撞檢測。用于正常碰撞(這是默認值)。
  • Continuous 對動態(tài)碰撞體(具有剛體)使用離散碰撞檢測,并對靜態(tài)碰撞體(沒有剛體)使用基于掃掠的連續(xù)碰撞檢測。設置為連續(xù)動態(tài) (Continuous Dynamic) 的剛體將在測試與該剛體的碰撞時使用連續(xù)碰撞檢測。其他剛體將使用離散碰撞檢測。用于連續(xù)動態(tài) (Continuous Dynamic) 檢測需要碰撞的對象。(此屬性對物理性能有很大影響,如果沒有快速對象的碰撞問題,請將其保留為 Discrete 設置)
  • Continuous Dynamic 對設置為連續(xù) (Continuous)連續(xù)動態(tài) (Continuous Dynamic) 碰撞的游戲?qū)ο笫褂没趻呗拥倪B續(xù)碰撞檢測。還將對靜態(tài)碰撞體(沒有剛體)使用連續(xù)碰撞檢測。對于所有其他碰撞體,使用離散碰撞檢測。用于快速移動的對象。
  • Continuous Speculative 對剛體和碰撞體使用推測性連續(xù)碰

官方文檔有點難懂,可以參考Unity-Rigidbody【剛體】組件-Collision Detection碰撞檢測模式

有時候開發(fā)游戲,對于高速運動的物體(比如:子彈/大炮,或者很高處自由落體的物體),即使再三確認加了Rigidbody組件,檢查了碰撞檢測的代碼完全沒有錯誤,但仍然會出現(xiàn) 物體直接穿過另一個物體 的問題, 則說明這個碰撞檢測的程序?qū)τ诟咚龠\動的物體而言會出錯。

Unity物體的Rigidbody組件提供了一個Collision Detection的屬性,該屬性用于更改物體的碰撞檢測模式————一共有三種模式可以選擇(選擇你想要的模式,底層碰撞檢測的算法均有差別)

  • Discrete適用于大部分剛體
  • Continuous適用于將有可能會被高速移動物體撞上的物體
  • Continuous Dynamic適用于高速移動的物體

另外參考官方文檔:連續(xù)碰撞檢測 (CCD)

5.Constraints 對剛體運動的限制:
  • Freeze Position 有選擇地停止剛體沿世界 X、Y 和 Z 軸的移動。
  • Freeze Rotation 有選擇地停止剛體圍繞局部 X、Y 和 Z 軸旋轉。

可以對物體在X、Y、Z三個軸上的位置/旋轉進行鎖定,即使受到相應的力也不會改變,但可以通過腳本來修改。否則物體在上升過程中會發(fā)生飄動(不僅y軸變化,X,Z也在變,不想這種現(xiàn)象,就把X,Z鎖定)

6.官方文檔提示

https://docs.unity.cn/cn/2019.4/Manual/class-Rigidbody.html

  • 兩個剛體的相對質(zhì)量決定了它們相互碰撞時的反應情況。
  • 使一個剛體具有比另一個剛體更大的質(zhì)量并不會使其在自由落體時降落得更快。要實現(xiàn)這一目的,請使用 Drag。
  • 較低的 Drag 值會讓對象看起來較重。較高的值會使其看起來較輕。Drag 的典型值為 .001(實心金屬塊)到 10(羽毛)之間。
  • 如果要直接操作對象的變換組件,但仍希望獲得物理效果,請附加剛體并將其設為 Kinematic。
  • 如果要通過變換組件移動游戲?qū)ο?,但希望接?Collision/Trigger 消息,必須將剛體附加到正在移動的對象。
  • 如果直接將對象的 Angular Drag 屬性設置為無窮大,無法使對象停止旋轉。
二、碰撞體
1. 盒型碰撞體

立方體的原始形狀

2. 球形碰撞體

球體的原始形狀

3. 膠囊碰撞體

膠囊體的原始形狀

4. 網(wǎng)格碰撞體

根據(jù)對象網(wǎng)格創(chuàng)建碰撞體,不能與另一個網(wǎng)格碰撞體碰撞。典型的解決方案是對所有移動的對象使用原始碰撞體,而對靜態(tài)背景對象使用網(wǎng)格碰撞體。

5. 車輪碰撞體

專門用于創(chuàng)建汽車或其他移動車輛,可參考官方教程:車輪碰撞體教程

https://docs.unity.cn/cn/2019.4/ScriptReference/WheelCollider.html

6. 地形碰撞體

處理與 Unity 地形系統(tǒng)的碰撞

三、碰撞控制
1.碰撞矩陣

image.png

參考
Unity的選擇碰撞--碰撞矩陣(Collision Matrix)

用代碼也可以控制:
https://docs.unity3d.com/cn/2019.4/ScriptReference/Physics.IgnoreLayerCollision.html
使碰撞檢測系統(tǒng)忽略 layer1 中的任何碰撞體與 layer2 中的任何碰撞體之間的所有碰撞。

注意,IgnoreLayerCollision 將重置受影響的碰撞體的觸發(fā)器狀態(tài),因此,您可能會收到調(diào)用該函數(shù)導致的 OnTriggerExit 和 OnTriggerEnter 消息。

您可以在 Physics Inspector 中為任何層組合設置項目默認值。

using UnityEngine;

public class Example : MonoBehaviour
{
    //Set the speed number in the Inspector window
    public float m_Speed;
    Rigidbody m_Rigidbody;

    void Start()
    {
        //Fetch the Rigidbody component from the GameObject
        m_Rigidbody = GetComponent<Rigidbody>();
        //Ignore the collisions between layer 0 (default) and layer 8 (custom layer you set in Inspector window)
        Physics.IgnoreLayerCollision(0, 8);
    }

    void Update()
    {
        //Press right to move the GameObject to the right. Make sure you set the speed high in the Inspector window.
        if (Input.GetKey(KeyCode.RightArrow))
        {
            m_Rigidbody.AddForce(Vector3.right * m_Speed);
        }

        //Press the left arrow key to move the GameObject to the left
        if (Input.GetKey(KeyCode.LeftArrow))
        {
            m_Rigidbody.AddForce(Vector3.left * m_Speed);
        }
    }

    //Detect when there is a collision
    void OnCollisionStay(Collision collide)
    {
        //Output the name of the GameObject you collide with
        Debug.Log("I hit the GameObject : " + collide.gameObject.name);
    }
}
2.IgnoreCollision

https://docs.unity3d.com/cn/2019.4/ScriptReference/Physics.IgnoreCollision.html
使碰撞檢測系統(tǒng)忽略 collider1 與 collider2 之間的所有碰撞。

這在某些情況下很有用。例如,防止飛彈與發(fā)射飛彈的對象發(fā)生碰撞。

注意,IgnoreCollision 不是持久性的。這意味著保存場景時忽略碰撞狀態(tài)將不會存儲在編輯器中。

如果 ignore 為 false,可能發(fā)生碰撞。將 ignore 設置為 true,可忽略碰撞。

using UnityEngine;
using System.Collections;

public class ExampleClass : MonoBehaviour
{
    public Transform bulletPrefab;

    void Start()
    {
        Transform bullet = Instantiate(bulletPrefab) as Transform;
        Physics.IgnoreCollision(bullet.GetComponent<Collider>(), GetComponent<Collider>());
    }
}
四、事件

當兩個對象碰撞時,可能會發(fā)生許多不同的腳本事件,具體取決于碰撞對象的剛體配置。以下圖表詳細列出了根據(jù)附加到對象的組件來調(diào)用的事件函數(shù)。某些組合僅會使兩個對象之中的一個對象受到碰撞的影響,但一般規(guī)則是物理特性不會應用于沒有附加剛體組件的對象。

發(fā)生碰撞檢測并在碰撞后發(fā)送消息

靜態(tài)碰撞體 剛體碰撞體 運動剛體碰撞體 靜態(tài)觸發(fā)碰撞體 剛體觸發(fā)碰撞體 運動剛體觸發(fā)碰撞體
靜態(tài)碰撞體
剛體碰撞體
運動剛體碰撞體
靜態(tài)觸發(fā)碰撞體
剛體觸發(fā)碰撞體
運動剛體觸發(fā)碰撞體

碰撞后發(fā)送觸發(fā)器消息

靜態(tài)碰撞體 剛體碰撞體 運動剛體碰撞體 靜態(tài)觸發(fā)碰撞體 剛體觸發(fā)碰撞體 運動剛體觸發(fā)碰撞體
靜態(tài)碰撞體
剛體碰撞體
運動剛體碰撞體
靜態(tài)觸發(fā)碰撞體
剛體觸發(fā)碰撞體
運動剛體觸發(fā)碰撞體
1.碰撞事件
using UnityEngine;
using System.Collections;
public class PhysicalTest : MonoBehaviour {
    // Use this for initialization
    void Start () {}
    void OnCollisionEnter(Collision collisionInfo)
    {
        Debug.Log ("enter");
        Debug.Log (collisionInfo.gameObject.name);
        Destroy (collisionInfo.gameObject);
    }
    void OnCollisionStay(Collision collisionInfo)
    {
        Debug.Log ("stay");
    }
    void OnCollisionExit(Collision collisionInfo)
    {
        Debug.Log ("Exit");
    }
}

當兩個物體發(fā)生碰撞的時候,可以看到函數(shù)進行了調(diào)用。其中OnCollisionEnter函數(shù)在剛體進入的時候,調(diào)用一次,只要兩個物體接觸到一起,會一直調(diào)用OnCollisionStay函數(shù)直到靜止。當兩個剛體離開的時候,調(diào)用OnCollisionExit函數(shù)??梢酝ㄟ^參數(shù)獲得與之發(fā)生碰撞的物體,并且進行對應的處理。

2.觸發(fā)事件

觸發(fā)器在生活有很多例子,假設進入到一些門口時,當我們踏入到一定范圍,門會自動打開,這其實就是觸發(fā)器在現(xiàn)實生活中的例子,游戲中依然也是,例如,人物走回家的時候會自動的恢復血量,這其實就是在使用觸發(fā)器

將BoxCollider上的IsTrigger進行勾選,使其成為一個觸發(fā)器,并且修改腳本如下:

void OnTriggerEnter(Collider colliderInfo)
{
    Debug.Log ("Trigger"+ 
        colliderInfo.GetComponent<Collider>().name);

}
void OnTriggerStay(Collider colliderInfo)
{
    //Debug.Log ("Trigger"+ colliderInfo.GetComponent<Collider>().name);
}
void OnTriggerExit(Collider colliderInfo)
{
    Debug.Log ("Trigger");
}

可以看到,勾選之后,雖然沒有發(fā)生碰撞反應,但是能夠監(jiān)測到物體的碰撞。

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容