关于Rigidbody,Collider和CharacterController三者之间的关系和用法的总结
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*()回调被调用的补充说明(来自:https://docs.unity3d.com/Manual/CollidersOverview.html):
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*()回调被调用的补充说明(来自:https://docs.unity3d.com/Manual/CollidersOverview.html):
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:
https://docs.unity3d.com/Manual/RigidbodiesOverview.html 中关于Sleeping的第二段。
在官方文档中提到了static collider,所谓static collider,就是那些不和Rigidbody一起使用的Collider(相反的,那些和Rigidbody一起使用的Collider就叫做dynamic collider)。这些Collider一般用在静止的物体上,不要试图去直接改变他们Transform的position(不要使用Translate()方法或者直接给position赋值),因为这样会对物理引擎造成很大的性能影响。(参见:https://docs.unity3d.com/Manual/CollidersOverview.html)。CharacterController是没有额外加Collider的,而NavMeshAgent的运动是由Navigation System来掌管的,也不是属于我们说的情况。
拓展阅读(非常重要):
https://docs.unity3d.com/Manual/CollidersOverview.html
关于Rigidbody,Collider和CharacterController三者之间的关系和用法的总结的更多相关文章
- silverlight Canvas、StackPanel、Grid三者之间的关系
学习 silverlight 首先Canvas.StackPanel.Grid 博客园里看到jailu的这篇文章整理得很好 贴下来: Silverlight提供了非常灵活的布局管理系统,让程序员和 ...
- 电脑结构和CPU、内存、硬盘三者之间的关系
前面提到了,电脑之父——冯·诺伊曼提出了计算机的五大部件:输入设备.输出设备.存储器.运算器和控制器. 我们看一下现在我们电脑的: 键盘鼠标.显示器.机箱.音响等等. 这里显示器为比较老的CRT显示器 ...
- 【Linux网络编程】TCP网络编程中connect()、listen()和accept()三者之间的关系
[Linux网络编程]TCP网络编程中connect().listen()和accept()三者之间的关系 基于 TCP 的网络编程开发分为服务器端和客户端两部分,常见的核心步骤和流程如下: conn ...
- 网络互联技术(2)——前篇—【转载】电脑结构和CPU、内存、硬盘三者之间的关系
原文链接:传送门 详细内容: 电脑结构和CPU.内存.硬盘三者之间的关系 前面提到了,电脑之父——冯·诺伊曼提出了计算机的五大部件:输入设备.输出设备.存储器.运算器和控制器. 我们看一下现在我们电脑 ...
- 转:spring data jpa、 hibernate、 jpa 三者之间的关系
原文链接:spring data jpa. hibernate. jpa 三者之间的关系 spring data jpa hibernate jpa 三者之间的关系 JPA规范与ORM框架之间的关系是 ...
- 程序中try、throw、catch三者之间的关系
c++程序中,采用一种专门的结构化处理逻辑的异常处理机制. 1.try语句 try语句块的作用是启动异常处理机制,检测try语句块中程序语句执行时可能出现的异常. try语句块总是与catch一同出现 ...
- Window系统、主函数和窗体函数这三者之间的关系
理解Window系统.主窗体.窗体函数这三者之间的关系,对于编写Windows程序十分重要. 主函数和窗体函数都是由Windows系统来调用的函数.仅仅只是主函数是程序启动之后.系统首先调用的函数: ...
- 5.Javascript 原型链之原型对象、实例和构造函数三者之间的关系
前言:用了这么久js,对于它的原型链一直有种模糊的不确切感,很不爽,隧解析之. 本文主要解决的问题有以下三个: (1)constructor 和 prototype 以及实例之间啥关系? (2)pro ...
- 【面向对象】----【prototype&&__proto__&&实例化对象三者之间的关系】(四)-----【巷子】
1.构造函数 a.什么是构造函数? 解释:通过关键字new 创建的函数叫做构造函数 作用:用来创建一个对象 废话少说直接上代码,首先我们还是创建一个构造函数人类 然后我们在创建两个实例,一个凡尘 一个 ...
随机推荐
- python网络爬虫《http和https协议》
一.HTTP协议 1.官方概念: HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web )服务器传输超文 ...
- Driver stacktrace: at org.apache.spark.scheduler.DAGScheduler.org$apache$spark$scheduler$DAGSchedul
在写Spark程序是遇到问题 Driver stacktrace: at org.apache.spark.scheduler.DAGScheduler.orgapacheapachesparksch ...
- JS中取得<asp:TextBox中的值
var s = document.getElementById("<%=txt_DaShen.ClientID %>").value; 注:txt_DaShen 为as ...
- Linux 下 mysql的基本配置
Linux 下 mysql的基本配置 2013年02月27日 ⁄ MySQL ⁄ 共 3000字 ⁄ 暂无评论 ⁄ 被围观 2,483 views+ 1. Linux mysql安装: $ yu ...
- bbs项目富文本编辑器实现上传文件到media目录
media目录是在project的settings中设置的,static目录是django自己使用的静态文件的上传目录,media目录是用户自定义上传文件的目录 # Django用户上传的文件都放在m ...
- 33-Java中的String,StringBuilder,StringBuffer三者的区别
转载自:https://www.cnblogs.com/su-feng/p/6659064.html StringBuilder 详解 (String系列之2) Java中的String,String ...
- PHP守护进程化
什么是守护进程? 一个守护进程通常补认为是一个不对终端进行控制的后台任务.它有三个很显著的特征:在后台运行,与启动他的进程脱离,无须控制终端.常用的实现方式是fork() -> setsid() ...
- css常见问题一
[1]禁止换行.class {word-break:keep-all;white-space:nowrap;}[2]强制换行.class{word-break:break-all;}普通容器中(Div ...
- springboot 日志1
技术交流群: 816227112 Spring Boot在所有内部日志中使用Commons Logging,但是默认配置也提供了对常用日志的支持,如:Java Util Logging,Log4J, ...
- VS2013中Nuget程序包管理器控制台使用入门(一)-准备环境(原创)
准备环境: 1.打开VS2013IDE集成开发环境. 2.新建一个Asp.net Mvc的项目,比如命名为:MvcApplication1 3.打开 菜单"工具"->&quo ...