Rigidbody 刚体

“大智,昨天我学习了物理系统,知道了碰撞体,那物理系统里面还有别的东西么?”
“你呀,太天真了,Collider只是物理系统的一部分。你看昨天学的Collider,他们都只是一个静态的碰撞体。我们昨天学习过物理系统很重要的是模拟物体的受力情况,物体根据物理规则运动呀。”
“那通过代码修改物体的位置不就能运动起来了么?”
“通过代码直接修改物体的位置并没有通过受力的方式改变物体,所以这种方式并没有应用到物理系统,要想让物体通过受力运动,我们首先要了解一下Rigidbody组件。物体只有添加了Rigidbody组件,才会对受力作出反应。小新,你现在先去看看Unity的文档,看看Rigidbody组件到底是什么吧!”
“收到,我马上就去看!”

小新马上打开Unity文档,找到了Rigidbody的介绍文档https://docs.unity3d.com/Manual/RigidbodiesOverview.html

Rigidbody组件可以让一个物体受到物理影响。比如添加Rigidbody组建后,物体会立马对重力作出反应。如果物体上还添加了Collider,物体在受到碰撞时也会移动。

“大智,我知道了!Rigidbody可以让物体对受力做出反应,但是我有点和Collider搞不清楚了。”
“这两个是初学者不太容易搞清楚的概念。Collider只是给物体加上了碰撞,让物体拥有了实体,而不是一个可以穿过去‘全息投影’。而Rigidbody是让物体拥有了动态受力的功能。所以我们一般称只有Collider没有Rigidbody的物体叫静态Collider。一般刚体物体上也会有Collider,因为需要和别的物体发生碰撞。如果没有Collider,即使刚体也不会和其他物体碰撞。”
“那是不是不应该给场景里所有的物体添加Rigidbody组件?”
“非常对,场景里有一些物体是基本不会动的,比如说一栋大楼,一块大石头等等,他们只需要阻挡别的物体别穿过他们就行了,所以它们只需要添加Collider就行。因为添加了Rigidbody组件后会带来很多的物理计算,所以只需要给会移动的物体添加Rigidbody就行。
“我明白了!我说呢怎么给所有物体添加了Rigidbody后卡的跑不起来呢,我去把我的吃鸡场景重新设置一下,嘿嘿!”
“你呀你呀,真是个急性子!顺便好好看一下刚体组件的各个参数!”
“知道啦!”

Rigidbody组件

小新认真看了Rigidbody组件的文档,并做了笔记:

 

Unity刚体详解_Unity教程

 

  • Mass 刚体的质量,单位是千克(kg)
  • Drag 空气阻力,0代表没有空气阻力,无限大的值代表物体会立即停下来(惯性消失)。
  • Angular Drag 物体受到一个扭力旋转时的阻力,0代表没有阻力,但是需要注意的是无限大的值并不能让物体立即停止旋转。
  • Use Gravity 是否受重力影响
  • Is Kinematic 选中时,物体不会受到物理物理引擎的影响,只能通过修改Transform移动物体。
  • Interpolate 插值,如果发现刚体移动有卡顿,可以尝试选择此选项。
    • None 不使用插值
    • Interpolate 根据上一帧的Transform进行平滑
    • Extrapolate 根据估算的下一帧的Transform进行平滑

 

  • Collision Detection 碰撞检测的方式,当你的刚体快速运动时,可能会出现穿透的现象,可以设置这个选项。
    • Discrete 离散检测,性能较高,默认值
    • Continuous 连续检测。使用此选项时,物体与其他动态Collider(刚体)使用离散检测;与其他静态Collider使用连续检测。如果其他刚体设置为了Continuous Dynamic,会使用连续检测和这个刚体进行碰撞检测。这个选项非常影响性能,如果没有快速运动物体的碰撞检测问题,保持Discrete设置

 

  • Continuous Dynamic 动态连续检测。如果其他物体是Continuous或Continuous Dynamic,与这个物体碰撞时会使用连续检测。也会和静态Collider使用连续检测。对于其他的collider(标记为Discrete的Rigidbody)使用离散检测。。用于快速移动的物体。
  • Constraints 约束刚体的运动
    • Freeze Position 选中后刚体不会在对应的轴上移动

 

  • Freeze Rotation 选中后刚体不会在对应的轴上旋转

小新看完之后,还是有一些地方不太清楚,又来骚扰大智。
“大智,刚体的Is Kinematic我明白了是什么,这个有什么用呢?加上刚体不就是为了受力么,为什么还要提供一个这个属性,关掉受力呢?”
“有些情况,我们不想让物体受力,但是仍然能够和其他物体发生碰撞,影响其他物体。比如这个物体上有动画,在播放动画的时候,我们想让动画来控制物体的位置。”
“明白了,但是感觉还是需要用到的时候再去理解。那这个Collision Detection该什么时候设置呢?是不是类似子弹这种情况?”
“说的很对,Collision Detection就是针对快速移动的小物体,比如说子弹,但是通常游戏射击并不用实体的子弹,因为子弹多的时候性能太差了,我可以给你推荐一个文章来看看:https://zhuanlan.zhihu.com/p/22105641
“谢谢智哥,我也发现了用刚体的话性能太差了,我去看看”

碰撞汇总

“大智,我发现有些情况两个物体发生了碰撞,但是并没有调用脚本中的代码,这是怎么回事?”
“哈哈,这时候我就要祭出大招了,给你两个表格,对照着看看是否会发生碰撞哈。”

Unity刚体详解_Unity教程_02

OnCollision消息

Unity刚体详解_Unity教程_03

OnTrigger消息

 

Rigidbody类

模拟GameObject对象在现实世界中的物理特性

对Rigidbody对象属性的赋值代码通常放在脚本的OnFixedUpdate()方法中


B、Rigidbody类实例方法

1、AddExplosionForce

public void AddExplosionForce(float explosionForce, Vetor3 explosionPosition, float explosionRadius);

public void AddExplosionForce(float explosionForce, Vetor3 explosionPosition, float explosionRadius, float upwardModifier);

public void AddExplosionForce(float explosionForce, Vetor3 explosionPosition, float explosionRadius, float upwardModifier, ForceMode mode);

#explosioForce为爆炸点施加的力的大小

#explosionPosition为爆炸点坐标,相对世界坐标系

#explosionRadius为爆炸作用力有效半径

#upwardsModifier为爆炸力作用点在y轴方向上的偏移

#mode为爆炸力的作用模式,默认为ForceMode.Force

此方法用于对刚体添加一个模拟爆炸效果的作用力。

设爆炸力大小为F,爆炸点坐标为E,有效半径为R,y轴的偏移量为y_m,刚体A的坐标为P,A受到的爆炸作用力为A.AddExplosionForce(F,E,R,y_m);

#爆炸力作用在刚体上的力的大小和方向是分开计算的;

爆炸力作用到A的大小为:

FA=(R-|EB|)*F/R,

#当爆炸点E固定时,刚体在某个范围移动时受到的爆炸力的大小可能不变

#当作用力半径R=0,所有接受爆炸点E作用的刚体收到的作用力大小都为F


2、AddForceAtPosition

public void AddForceAtPosition(Vector3 force, Vector3 position);

public void AddForceAtPosition(Vector3 force, Vector3 position, ForceMode mode);

#force为扭矩向量

#position为作用点坐标值

#mode为力的作用方式

此方法用于为参数position点增加一个力force,其参考坐标系为世界坐标系,作用方式为mode,默认值为ForceMode.Force

该方法与AddForce不同之处在于,AddForce方法对刚体施加力时不会产生扭矩使物体发生旋转,而AddForceAtPosition方法是在某个坐标点对刚体施加力,这样很可能会产生扭矩使刚体产生旋转

#当力的作用点在刚体重心时,刚体不发生旋转

#当力的作用点不在刚体重心时,刚体发生旋转,但当作用力的方向晋国刚体的重心坐标时不发生旋转


3、AddTorque

public void AddTorque(Vector3 torque) ;

public void AddTorque(Vector3 torque, ForceMode mode) ;

public void AddTorque(float x, float y, float z);

public void AddTorque(float x, float y, float z, ForceMode mode);

参数torque为扭矩向量,参数mode为力的作用方式

此方法用于给刚体添加一个扭矩torque,扭矩的作用力方式由mode决定,默认为ForceMode.Force


不同形状的刚体及不同的转轴,其转动惯量1的计算方式是不同的。

刚体有最大角速度的限制,默认值为7.0f,可以通过属性maxAngularVelocity更改刚体的最大角速度


4、ClosestPointOnBounds

public Vector3 ClosestPointOnBounds(Vector3 position);

参数position为爆炸点坐标

此方法用于求爆炸点到刚体Colloder表面的作用点,通常用在AddExplosionForce中计算爆炸力的大小

返回值为刚体Collider表面上的某一点,而不是Mesh上的点


5、GetPointVelocity

public Vector3 GetPointVelocity(Vector3 worldPoint);

worldPoint为世界坐标系中的点坐标

此方法用于获取世界坐标系中worldPoint点在刚体局部坐标系中对应位置的速度

往往是刚体重心的移动速度和点绕刚体重心的角速度


6、GetRelativePointVelocity

public Vector3 GetRelativePointVelocity(Vector3 relativePoint);

参数relativePoint为刚体自身坐标系中的点坐标

此方法用于获取刚体自身坐标系中relativePoint点的速度,速度的计算会受刚体角速度的影响

此方法和GetPointVelocity作用类似,只是GetPointVelocity使用世界坐标系中的坐标来确定位置,而此方法是使用自身坐标系中的坐标来确定位置。

可以将上述两种方法的点理解为刚体子类物体的重心坐标值。


7、MovePosition

public void MovePosition(Vector3 postion);

刚体的位置移动,通常用在刚体失去动力学模拟的情况下,即isKinematic为true时


8、Sleep

public void Sleep();

此方法可使刚体进入休眠状态,且至少休眠一帧


9、SweepTest

public bool SweepTest(Vector3 direction, out RaycastHit hitInfo);

public bool SweepTest(Vector3 direction, out RaycastHit hitInfo, float distance);

参数direction为探测方向,参数distance为有效探测距离,默认为无穷大

此方法用于检测在刚体的direction方向是否有碰撞器对象,且对象的有效探测距离不大于distance

#distance为A物体右表面到B物体左表面的距离,而非它们重心坐标之间的距离

#B物体只要含有Collider组件即可,无需含Rigidbody组件

#direction的方向为A在世界坐标系中的方向

#SweepTest的返回结果只是第一个被探测到的物体


10、SweepTestAll

public RaycastHit[ ] SweepTestAll(Vector3 direction);

public RaycastHit[ ] SweepTestAll(Vector3 direction, float distance);

此方法用于探测刚体的direction方向的distance距离内是否含有碰撞器,并返回所有探测到的物体的RaycastHit

与SweepTest的不同之处在于返回每个探测到的物体的RaycastHit


11、WakeUp

public void WakeUp( )

此方法用于将刚体从休眠状态唤醒,除了调用WakeUp方法外,在发生以下4种情况时,刚体会被自动唤醒

①其他刚体与休眠种的刚体发生了碰撞

②使用关节连接的其他刚体发生了移动

③刚体的属性发生了改变

④给休眠中的刚体施加了一个外力