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

上一篇:Kivy A to Z -- 怎样从python代码中直接訪问Android的Service


下一篇:mysql date_format()函数