[Unity 3D] Unity 3D 裏的碰撞檢測
Unity 3D裏兩個碰撞體之間發生碰撞可以用OnCollision族函數和OnTrigger族函數來獲知和處理。Unity官方給出了兩張可發生碰撞的組合表:
Collision detection occurs and messages are sent upon collision | ||||||
Static Collider | Rigidbody Collider |
Kinematic Rigidbody Collider |
Static Trigger Collider |
Rigidbody Trigger Collider |
Kinematic Rigidbody Trigger Collider |
|
Static Collider | Y | |||||
Rigidbody Collider | Y | Y | Y | |||
Kinematic Rigidbody Collider | Y | |||||
Static Trigger Collider | ||||||
Rigidbody Trigger Collider | ||||||
Kinematic Rigidbody Trigger Collider |
Trigger messages are sent upon collision | ||||||
Static Collider | Rigidbody Collider |
Kinematic Rigidbody Collider |
Static Trigger Collider |
Rigidbody Trigger Collider |
Kinematic Rigidbody Trigger Collider |
|
Static Collider | Y | Y | ||||
Rigidbody Collider | Y | Y | Y | |||
Kinematic Rigidbody Collider | Y | Y | Y | |||
Static Trigger Collider | Y | Y | Y | Y | ||
Rigidbody Trigger Collider | Y | Y | Y | Y | Y | Y |
Kinematic Rigidbody Trigger Collider | Y | Y | Y | Y | Y | Y |
不過,生搬硬背顯然不是一個有理想的死程應該做的事情。那麼,要如何理解和記憶Unity 3D裏的碰撞發生條件呢,歸根結底只要理解了以下五個概念就搞定了:
Collider
Rigidbody
Static
Kinematic
Trigger
Collider——很簡單,就是碰撞盒,有碰撞盒纔有碰撞,所有碰撞的參與者都必須要有至少一個碰撞盒才行;
Rigidbody——剛體,當剛體存在時物理引擎就會介入,對於引擎來說,碰撞必須要有剛體參與(原因後述),但是並不要求碰撞的雙方都是剛體,只要動的一方是剛體就OK,如果雙方都有位移或者旋轉,那麼只要有一方是剛體就OK;
Static——這其實只是一個描述,或者說概念,任何不是剛體的物體,引擎都認爲它永遠是Static的,即靜止的,哪怕它正在發生位移或者旋轉;而剛體,引擎認爲它是“能運動的”,也就是說,剛體雖然可以保持靜止的狀態,但是一旦發生位移或者旋轉,引擎就會認爲它動了;對於兩個靜止的物體,引擎認爲他們不會發生碰撞,也就不會處理他們之間碰撞盒的任何交疊,這裏包括兩個非剛體,也包括一個保持靜止的剛體和一個非剛體。這就是碰撞發生的雙方中運動的那一方必須要是剛體的原因。
Kinemtic——這是一個描述,同時也是Rigidbody的一個屬性。被標記爲Kinematic的剛體就成爲了一個純運動學物體,這意味着它不再受外力作用,它的運動狀態直接由位置和旋轉來決定。當然,一個Kinematic的剛體還是可以對外產生作用力的,也就是說,它可以推動其他剛體,但是其他剛體對它無可奈何。
Trigger——這也是一個描述,同時是Collider的一個屬性。被標記爲Trigger的碰撞盒不再具備物理特性,這與Kinematic不一樣,Kinematic的剛體仍就是一個物理體,而Trigger只代表一個區域,或是一個引子(這取決於它在碰撞中擔當的角色,在碰撞中,如果它是運動的那一方,那麼它就是一個引子,只要它碰撞到了任何物體,不論靜止還是運動,都會被觸發;如果它是靜止的那一方,那麼它就是一個區域,所有進入此區域的運動物體都會觸發它,這裏的“運動”不是單純的位移或者旋轉,參照Static的定義)。
好了,下面拿着這五個概念對照的看看Unity官方提供的表單。
先看Collision表,Collision是物理引擎管轄下的碰撞,即便是你不處理OnCollision族函數,物理引擎也會爲碰撞雙方計算作用力和作用力下的運行。由於Trigger標記下的物體不再是物理體,任何標記爲Trigger的物體都不會觸發Collision。物理碰撞的發生必然是有一方在運動,因此如果雙方都被引擎認爲是靜止的物體,是不可能發生Collision的,因此雙方都是非剛體(表中的Static Collider)時無法觸發Collision。 這裏還有一個小問題,光從Collision表裏是看不出來的,那就是在Static Collider和Rigidbody Collider之間,即便Collision表裏畫的是對鉤,當碰撞裏有位移或者旋轉的那一方是Static Collider而不是Rigidbody Collider的時候,Collision是不會觸發的哦,原因很簡單,就是前面說的引擎認爲物體靜止的問題,沒有位移或者旋轉的Rigidbody是靜止的,而非剛體也是靜止的,兩個靜止的物體無法發生碰撞 。至於Kinematic Rigidbody Collider,由於它本身不會受外力作用,而Collision是要能夠產生物理作用力的,所以只有當能夠受外力作用的物體跟它相撞時纔會觸發Collision,因此,沒有作用力概念的Static Collider和不受外力作用的Kinematic Rigidbody Collider是無法跟它產生Collision的。
再看Trigger表,要觸發Trigger就至少要有一個被標記爲Trigger的碰撞盒存在,因此雙方都沒有被標記Trigger時,Trigger是不會觸發的。即便有被標記爲Trigger的物體存在,如果雙方都被引擎認爲是靜止狀態,同樣不會觸發Trigger(還是那個道理,兩個被引擎認爲靜止的物體,是無法發生碰撞的),因此Static Collider跟Static Trigger Collider之間,兩個Static Trigger Collider之間,都不會觸發Trigger。跟Collision表一樣,這裏也有一個小問題光從表裏看不出來,就是當Static Collider遇上Rigidbody(Kinematic)時,不管誰是Trigger,運動的一方必須要是Rigidbody(Kinematic)才能觸發Trigger,道理同上 。
唯一一個例外情況:
如果雙方初始化在了一起,也就是說雙方初始化出來碰撞盒就發生了交疊,這時候物理引擎網開一面,對於Collision來說,只要雙方都不是Trigger,且有一方是非Kinematic的Rigidbody(也就是說Collision表裏畫了對鉤的組合),就必然會發生一次Collision,對於Trigger來說,只要雙方有一方是Trigger,且有一方是Rigidbody(Kinematic)(亞也就是Trigger表裏畫了對鉤的組合),那麼就必然會觸發一次Trigger。當然這僅限初始化的那一幀,之後就一切迴歸正軌。
不過Unity 3D在這裏有一個bug,當雙方一個是非Kinematic的Rigidbody,另一方是Static Collider也就是非剛體,且碰撞盒在初始化時就交疊在了一起的話,除了一開始的那一幀會觸發Collision外,之後剛體不動而非剛體動,仍有一定機率會觸發Collision(按規則說是不能觸發的),具體表現就是非剛體可以推着剛體走。