博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
关于Rigidbody,Collider和CharacterController三者之间的关系和用法的总结
阅读量:5235 次
发布时间:2019-06-14

本文共 5751 字,大约阅读时间需要 19 分钟。

Rigidbody:多用在“物体”上,因为“物体”都是“死”的,他们的运动一般都是靠物理系统。所以对于Rigidbody的移动,不要用Translate(),要用各种“力”, 比如:Rigidbody的AddForce()方法,通过“力”来让它移动。另外,Rigidbody可以和NavMeshObstacle合用,因为后者也是用在“物”上的,但是一般不要和NavMeshAgent合用,因为这两个都会控制物体的运动,这样会有race condition。如果非要合用,请勾选Is Kinematic,由此看来如果Rigidbody的Is Kinematic属性被勾选了,那么Rigidbody就可以和任何其他的Component合用了,比如:NavMeshAgent,CharacterController。

Collider:定义了一个物体的形状,而我们的碰撞检测就是根据这个形状来进行的,随意Collider是碰撞检测的基础,几乎Unity中所有的物体都需要Collider。就算我们使用CharacterController一般会删掉原来的Collider,不过CharacterController本身自带了一个Capsule Collider。Collider分为static collider和dynamic collider,前者表示没有Rigidbody的collider,后者表示有Rigidbody的collider,static collider的物体最好是静止的物体,不要通过改变他的transform的position来使它运动,这样不仅会给物理引擎造成很多性能损失,而且会产生一些无法预测的行为。所以如果我们非要一个有collider的物体通过我们的脚本(比如通过Translate()方法)移动,并且不希望被物理引擎控制,那么我们需要给这个collider配上一个勾选了Is Kinematic的Rigidbody。因为Rigidbody的Is Kinematic就是让这个Rigidbody不受物理引擎的控制。结论:在游戏中,对于那些可能将来会移动的物体,我们不仅要加Collider,还要加上Rigidbody,如果希望是被物理引擎控制,就不勾选Rigidbody的Is Kinematic,如果希望不被物理引擎控制,希望通过自己的代码或者动画来控制,就勾选Rigidbody的Is Kinematic,而且这个属性还可以在脚本中随时改变,从而实现“ragdoll effect”,“ragdoll effect”类似于CS里面的效果,大部分时间物体的运动是通过脚本和动画控制的,如果遇到爆炸等,物体的运动就可以被物理系统接管了,这个时候开启Is Kinematic最合适了。

CharacterController:多用在“角色”上,因为“角色”多是“活”的(比如:游戏中的主角,NPC什么的),他们的运动要么是玩家控制,要么是脚本控制,所以一般不需要由物理系统来控制,如果由物理系统控制,反而使得游戏的操作性下降了。由玩家控制的“角色”肯定不要用Rigidbody,要用CharacterController。如果NPC非要用Rigidbody,那么请勾选Is Kinematic。使用了CharacterController以后,就不要用Translate()来移动物体了,要用它自己提供的Move()方法来移动物体。否则会有一些“诡异”的问题。

CharacterController不对任何“力”产生作用,同时也不对然和物体施加“力”,即使那个物体是Rigidbody。

Rigidbody会对“力”产生响应,如果一个物体加上了Rigidbody,首先会直接对“重力”产生响应,如果再加上Collider,就会对其他“力”产生响应了。同时如果使用Translate()移动Rigidbody,那么它会对其他的Rigidbody在碰撞的时候自动施加一个“力”。


Collider中Is Trigger的优先级高于Rigidbody(不管这个被标记为Is Trigger的Collider和Rigidbody是不是在同一个GameObject上)。因为Rigidbody是根据Collider来进行物理模拟的,Collider是Rigidbody的基础,所以如果这个Collider是Trigger,由于Trigger只是通过调用OnTrigger*()函数来响应碰撞这个行为,而不会去响应任何实质性的碰撞(所谓的实质碰撞,就是能被观察到的碰撞,比如碰撞之后产生运动,碰撞之后阻止物体穿过等等)。所以就算Rigidbody在,也发挥不了作用(OnCollision*()函数不会调用,同时也不会产生物理运动,也不会阻止物体穿过,反正任何可见的碰撞效果都没有)。

同理,Collider中Is Trigger的优先级也高于CharacterController,不过Collider和CharacterController一般不放在一起,所以这里指的是对方的物体上Collider的Is Trigger。

CharacterController(不要再加Collider,CharacterController有自带的Capsule Collider。并且使用Move()方法移动物体) 

用CharacterController去碰撞另一个物体,如果被碰撞的物体有Collider,并且Is Trigger没有勾选,那么无论这个物体是不是Rigidbody,CharacterController都会被这个物体“挡”下来,并且只会触发他自己的OnControllerColliderHit()这个回调函数(也就是说,如果被碰撞的物体或者它自己有OnTrigger*(),OnCollision*()这种函数,都不会被触发)。

所以如果我们想要实现一个CharacterController推箱子的游戏,那么首先这个箱子必须是Rigidbody,并且Collider不是Is Trigger,而这个“推力”需要在CharacterController的OnControllerColliderHit()这个函数中“发出”了。

如果被碰撞的物体Collider的Is Trigger方法勾选了,那么由于Is Trigger只是将Collider当成了一个“触发器”,而不会响应如何的实质碰撞(所谓的实质碰撞,就是能被观察到的碰撞,比如碰撞之后产生运动,碰撞之后阻止物体穿过等等),所以CharacterController会穿过被碰撞的物体,并且OnControllerColliderHit()这个回调不会起作用,取而代之的是双方的OnTrigger*()函数会被调用。

Rigidbody(如果勾选了Is Kinematic,那么这个Rigidbody就不受物理引擎控制了) 

一个物体一旦加上了Rigidbody,那么就可以立刻受到“重力”的影响,如果再加上Collider,那么就可以受到别的“力”的影响,由于Collider的Is Trigger的优先级较高,所以,如果Collider是Is Trigger(不管这个Is Trigger的Collider是不是和Rigidbody在一个物体上,反正只要碰撞双方出现了Is Trigger),那么这个Rigidbody就不会产生实质性的碰撞(所谓的实质碰撞,就是能被观察到的碰撞,比如碰撞之后产生运动,碰撞之后阻止物体穿过等等)。并且OnTrigger*()被调用,而不是OnCollision*()。

关于Rigidbody的OnCollision*()回调被调用的补充说明(来自:): 

With normal, non-trigger collisions, there is an additional detail that at least one of the objects involved must have a non-kinematic Rigidbody (ie, Is Kinematic must be switched off). If both objects are kinematic Rigidbodies then OnCollisionEnter, etc, will not be called. With trigger collisions, this restriction doesn’t apply and so both kinematic and non-kinematic Rigidbodies will prompt a call to OnTriggerEnter when they enter a trigger collider.

Rigidbody:OnCollisionEnter(Collision c), OnCollisionStay(Collision c), OnCollisionExit(Collision c)

Collider Is Trigger: OnTriggerEnter(Collider c), OnTriggerStay(Collider c), OnTriggerExit(Collider c)

CharacterController: OnControllerColliderHit(ControllerColliderHit c)

产生碰撞(可以看见效果的碰撞或者像Is Trigger的Collider那样不可见效果的碰撞)的一般条件(不是必要条件,因为有一个例外,见后面的解释)是碰撞双方都要有Collider(不管是否是Is Trigger),并且其中至少有一个有Rigidbody或者CharacterController。这个时候碰撞产生,并且调用相应的回调函数。如果出现多个函数都可以调用的情况,看下面的优先级。

最高优先级:有Is Trigger的Collider参与的碰撞只会调用双方的OnTrigger*()函数,且不会产生实质碰撞(所谓的实质碰撞,就是能被观察到的碰撞,比如碰撞之后产生运动,碰撞之后阻止物体穿过等等)。

次高优先级:有CharacterController参与且没有Is Trigger的碰撞只会调用CharacterController的(如果被碰撞的也是CharacterController,那么他的OnControllerColliderHit()也会被调用)OnControllerColliderHit()函数。且会产生CharacterController被物体“档”下来的效果,不过除此之外没有其他任何物理效果。

最低优先级:有Rigidbody参与的碰撞,并且没有CharacterController和Is Trigger的Collider,会调用碰撞双方的OnCollision*()回调,并且由物理系统模拟碰撞之后的物理运动。

关于Rigidbody的OnCollision*()回调被调用的补充说明(来自:): 

With normal, non-trigger collisions, there is an additional detail that at least one of the objects involved must have a non-kinematic Rigidbody (ie, Is Kinematic must be switched off). If both objects are kinematic Rigidbodies then OnCollisionEnter, etc, will not be called. With trigger collisions, this restriction doesn’t apply and so both kinematic and non-kinematic Rigidbodies will prompt a call to OnTriggerEnter when they enter a trigger collider.

为何Collider的Is Trigger的优先级最高?因为Collider是一切碰撞的基础。

例外:如果一个运动的物体A(通过改变Transform来使得它运动)和静止的物体B发生碰撞,A只有Collider,并且不是Is Trigger,B是Rigidbody,并且Collider也不是Is Trigger,那么任何回调函数都不回被触发,并且没有物理模拟碰撞效果,A会穿过B。但是如果A和B都是静止的,并且也开始就“挨着”,那么这个时候又会发生碰撞了,由于没有Is Trigger,所以是双方的OnCollisionEnter()被调用。

这个例外在官方文档被称为fail to sleep: 

 中关于Sleeping的第二段。

在官方文档中提到了static collider,所谓static collider,就是那些不和Rigidbody一起使用的Collider(相反的,那些和Rigidbody一起使用的Collider就叫做dynamic collider)。这些Collider一般用在静止的物体上,不要试图去直接改变他们Transform的position(不要使用Translate()方法或者直接给position赋值),因为这样会对物理引擎造成很大的性能影响。(参见:)。CharacterController是没有额外加Collider的,而NavMeshAgent的运动是由Navigation System来掌管的,也不是属于我们说的情况。

拓展阅读(非常重要): 

转载于:https://www.cnblogs.com/mcyushao/p/9653020.html

你可能感兴趣的文章
Modbus TCP 示例报文
查看>>
spring的annotation
查看>>
go 学习笔记(4) ---项目结构
查看>>
如何解决ORA-01033问题(转)
查看>>
分割线细线
查看>>
java 中的一些运算符问题
查看>>
c# 操作ftp
查看>>
css切换--使用cookie
查看>>
C#运算符之异或运算
查看>>
C语言与C++ <string.h> memchr出现的问题
查看>>
java中静态代码块的用法 static用法详解
查看>>
用于代码检查的错误列表
查看>>
Java线程面试题
查看>>
C#2.0 读word的多个表格到DataGridView或是其它控件 XP Vista
查看>>
sql script: Graphs, Trees, Hierarchies and Recursive Queries
查看>>
Paper Reading: Relation Networks for Object Detection
查看>>
Android中点中overlay弹出带尾巴的气泡的实现
查看>>
Mybatis接口中传递多个参数
查看>>
Dreamweaver层使用八定律
查看>>
Java IO流学习总结
查看>>