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(按规则说是不能触发的),具体表现就是非刚体可以推着刚体走。