Simple Collider With Rigidbody In Unity
本文主要是简述Unity引擎中
collider是否需要配合rigidbody使用的问题;
kinematic rigidbody;
trigger
触发OnCollisionXxx()与OnTriggerXxx()的条件;
资料均来自Unity文档,内容面向新手,较为基础。
Kinematic rigidbody collider
在Unity中,使一个gameobject移动的途径主要有两种:直接更改transform的position实现,以及通过物理引擎驱动实现。前者对于所有gameobject都适用,每个gameobject都有transform,后者需要添加rigidbody组件,使得gameobject按照物理的方式移动。
在Unity中,若希望一个gameobject能被Unity的物理引擎驱动,则应该通过rigidbody组件实现gameobject的移动。否则,只通过transform实现gameobject的移动。
这一点,对于带有collider组件的gameobject同样有效(下文把带有collider组件的gameobject称为collider)。但是,在细节上有进一步的限制。可以试想一下,如果一个collider在场景中是移动的,且不希望其受外力影响,而是直接通过更改transform实现移动,我们需要为其添加rigidbody组件吗? 如果根据文章第一段的内容,会得出不需要rigidbody组件的结论。但是,实际上,Unity希望开发人员为这个collider添加rigidbody组件,并且将rigidbody组件的Is Kinematic设为true。要理解这样做的原因,需要搞清楚两个概念:static collider,以及kinematic rigidbody。
Static collider
Unity会将没有rigidbody组件的collider视为static collider,这里的static指的是该collider在当前场景的整个生命周期中,其transform的position与scale不会更改,且不会切换enable/disabled状态(collider有一个bool类型的enabled属性,设为false则为disabled,collider无法与其他collider碰撞),反之,视为dynamic collider。Unity基于这个假设对物理引擎进行了优化,为所有non-rigidbody collider(没有rigidbody组件的collider)进行缓存,进而提升物理引擎的性能,因此,一旦移动static collider则会造成额外的性能开销,甚至可能导致无法解释的问题,原本对static collider的优化反而成了负担。
然而,Unity没有强制限制non-rigidbody collider不能移动(这应该是为了保证引擎的灵活性),由于rigidbody对于collider起着标记的作用,Unity会把没有rigidbody的collider认为是static collider,把有rigidbody的collider认为是dynamic collider,Unity根据这个假设进行优化。因此,开发人员需牢记一个准则,即为了保证物理引擎的效率,不要为不会移动且scale不会变化且不会切换enabled/disabled的collider添加rigidbody组件,以及为所有可能会移动或scale会变化或会切换enabled/disabled的collider添加rigidbody组件。
但是,为移动的collider添加rigidbody组件,带来了另一个问题,原本不希望受外力影响的collider有了rigidbody组件后会受到外力影响,这该如何解决?—— 将rigidbody的Is Kinematic打开。
Kinematic rigidbody
打开Is Kinematic的rigidbody(称为kinematic rigidbody)不会受到外力的作用,因此,kinematic rigidbody不能通过AddForce()、velocity等物理方式来实现运动,只能通过更改transform与动画驱动的方式来实现gameobject的运动。
下面图示中,左边的是non-kinematic rigidbody,其会受到重力作用而做自由落体运动。右边的是kinematic rigidbody,由于其不受外力作用,因此,不会下落。
由于kinematic rigidbody不受外力作用,因此non-kinematic rigidbody无法推动kinematic rigidbody。如下
但是,kinematic rigidbody可以推动non-kinematic rigidbody。
至此,文章开头的问题已经得到了解释,对于无需外力作用但是需要进行移动的collider,应该添加rigidbody来标记其不是一个static collider,并且打开Is kinematic保证其不受外力作用,且通过transform控制其移动。这样的collider称为kinematic rigidbody collider,如移动的平台,为了使平台上能放置其他游戏对象且能在场景中非物理的移动,应该将其设为kinematic rigidbody collider。
More about kinematic rigidbody
-
Kinematic rigidbody除了不受外力作用外,也不受joints的束缚,但是可以通过joints对其他non-kinematic rigidbody进行束缚。
-
可以通过脚本设置rigidbody的
IsKinematic属性。这对于布娃娃系统很有用,当角色是通过动画实现运动时,将IsKinematic设为true,当要使其做出物理反应时,将IsKinematic设为false。 -
Kinematic rigidbody collider不会被static collider阻拦,会穿过static collider。
-
两个kinematic rigidbody collider交汇无法触发碰撞效果,而是直接穿过。但是,non-kinematic rigidbody collider与kinematic rigidbody collider交汇能触发碰撞效果。
如下,两个non-kinematic rigidbody collider做相对运动交汇时互相穿过,并不会碰撞,此时
OnCollisionXxx()也不会触发。
Trigger
有时,我们不希望一个gameobject有碰撞效果,使其他gameobject能够穿过这个gameobject,但是仍需要collider的碰撞回调(OnCollisionXxx())的功能,这种情况下可以打开collider的Is Trigger,并且通过OnTriggerXxx()来处理交汇时的操作,这样的collider称为trigger,比如待收集的物品,角色可以拾取物品,但是不能被物品阻隔,物品被拾取后还需触发特定事件(如物品数加一),因此,应当将待收集物品设为trigger。如若trigger是运动的,与前文提到理由相同,还应该为其添加kinematic rigidbody组件。
如下,橙色collider每穿过紫色trigger一次,触发OnTriggerXxx(),右上角的count计数就增加1。
触发OnCollisionXxx()与OnTriggerXxx()的条件
两个做相对运动且交汇的collider要触发符合物理的碰撞效果的前提是两个collider均不是trigger且至少一个collider是non-kinematic rigidbody,在这种情况下,才能触发collider的OnCollisionXxx()回调方法。
触发OnTriggerXxx()的条件没有上面那么严格,只要至少一个collider是trigger且至少一个collider是rigidbody即可触发。
总结
关于collider是否使用rigidbody,是否打开Is Kinematic。
关于使用collider还是trigger。