物理系统之碰撞检测
1.刚体
碰撞产生的必要条件:
- 两个物体都有碰撞器 Collider
- 至少一个物体有刚体
RigidBody组件信息:
1.Mass:质量 默认为千克,质量越大惯性越大
2.Drag:空气阻力 根据力移动对象时影响空气阻力大小 ,0 表示没有空气阻力
3.Augular Drag:旋转阻力 根据扭矩旋转对象时影响对象的空气阻力大小,0 表示没有阻力
4.Use Gravity:是否受重力影响
5.Is Kinematic:是否设置为运动学
如果启用,对象将不会被物理引擎驱动,只能通过 Transform 对其进行操作,对于移动平台,或者如果要动画附加了 HingeJoint 的刚体,此属性将非常有用
6.Interpolate:插值运算
-
None:不应用插值运算
-
Interpolate:根据前一帧的变换来平滑变换
-
Extrapolate:插值运算
根据下一帧的估计变换来平滑变换,若物理帧时间过长,此效果将不好
7.Collison Detection:碰撞检测模式
-
None:Discrete:离散检测
-
Interpolate:根据前一帧的变换来平滑变换
-
Discrete:离散检测
对场景中的所有其他碰撞体使用离散碰撞检测,其他碰撞体在测试碰撞时会使用离散检测。用于正常碰撞(默认值)
-
Continuous:连续检测
对动态碰撞体(具有刚体)使用离散碰撞检测
对静态碰撞体(没有刚体)使用连续碰撞检测
设置为连续动态的刚体,将在测试与该刚体的碰撞时使用连续碰撞检测(物理性能消耗较大,物体运动缓慢时请设置为 Discrete)
其他刚体将使用离散碰撞检测
-
Continuous Dynamic:连续动态检测
对设置为连续和连续动态碰撞的对象使用连续碰撞检测
对静态碰撞体(没有刚体)使用连续碰撞检测
对其他碰撞体使用离散碰撞检测
用于快速移动的对象
-
Continuous Speculative:连续推测检测
对刚体和碰撞体使用推测性连续碰撞检测
通常比连续碰撞检测的成本更低
无刚体碰撞盒 | Discrete | Continuous | Continuous Dynamic | Continuous Speculative | |
无刚体碰撞盒 | 不检测碰撞 | Discrete | Continuous | Continuous | Continuous Speculative |
Discrete | Discrete | Discrete | Discrete | Discrete | Continuous Speculative |
Continuous | Continuous | Discrete | Discrete | Continuous | Continuous Speculative |
Continuous Dynamic | Continuous | Discrete | Continuous | Continuous | Continuous Speculative |
Continuous Speculative | Continuous Speculative | Continuous Speculative | Continuous Speculative | Continuous Speculative | Continuous Speculative |
性能消耗关系:Continuous Dynamic > Continuous Speculative > Continuous > Discrete
8.Constrains:对刚体运动的约束
- Freeze Position:限制刚体在世界坐标轴下 X、Y、Z 轴的移动
- Freeze Rotation:限制刚体在世界坐标轴下 X、Y、Z 轴的旋转
9.Info:用于显示参数的面板,不修改里面的值
2.碰撞器 Collider
1.碰撞器种类
- 盒状碰撞器 Box Collider(常用)
- 球状碰撞器 Sphere Collider(常用)
- 胶囊碰撞器 Capsule Collider(常用)
- 网格碰撞器 Mesh Collider
- 轮胎碰撞器 Wheel Collider
- 地形碰撞器 Terrain Collider
2.共同参数
-
Is Trigger:是否为触发器
如果启用,则该碰撞体用于触发事件,并被物理引擎所忽略
主要用于进行没有物理效果的碰撞检测
-
Material:物理材质
可以确定碰撞体和其他对象碰撞时的交互(表现)方式
-
Center:碰撞体的中心偏移位置
3.常用碰撞器
1.Box Collider
Size:碰撞体在 X、Y、Z 方向上的大小
2.Sphere Collider
Radius:球形碰撞体的半径大小
3.Capsule Collider
- Radius:胶囊体的半径
- Height:胶囊体的高度
- Direction:胶囊体在对象局部空间中的轴向
4.异形物体使用多种碰撞器组合
刚体对象的子对象碰撞信息参与碰撞检测(即父物体添加 Rigid Body,子物体设置 Collider。)
5.不常用碰撞器
1.Mesh Collider
-
Convex:是否为凸面的
勾选后,该 Mesh Collider 将会与其他 Mesh Collider 发生碰撞,最多支持 255 个三角面片
如果该对象添加了刚体 Rigid Body,则该选项必须勾选,否则会报错
- Cooking Options:物理引擎对网格的处理方式(不常用)
- Mesh:引用需要用于碰撞的网格
2.Wheel Collider
赛车游戏中使用,其他时候不常用
注意:添加 Wheel Collider 后一定要添加 Rigid Body(或在父物体添加),否则将失效
3.Terrain Collider
地形系统中使用
性能较为低下,很少使用
3.物理材质
在 Project 中创建物理材质 Physics Material
1.Dynamic Friction
已在移动时使用的摩擦力。通常为О到1之间的值。值为零就像冰一样,值为1将使对象迅速静止(除非用很大的力或重力推动对象)
2.Static Friction
当对象静止在表面上时使用的摩擦力。通常为О到1之间的值。值为零就像冰一样,值为1将导致很难让对象移动。
3.Bounciness
表面的弹性如何?值为О将不会反弹。值为1将在反弹时不产生任何能量损失,预计会有一些近似值,但可能只会给模拟增加少量能量。
4.Friction Combine(两个碰撞对象的摩擦力的组合方式。)
- Average 对两个摩擦值求平均值。
- Minimum 使用两个值中的最小值。
- Maximum 使用两个值中的最大值。
- Multiply 两个摩擦值相乘。
5.unce Combine
两个碰撞对象的弹性的组合方式。其模式与Friction Combine模式相同
4.碰撞检测函数
1.知识点回顾
- 如何让两个游戏物体之间产生碰撞(至少一个刚体 和 两个碰撞器)
- 如何让两个物体之间碰撞时表现出不同效果(物理材质)
- 触发器的作用是什么(让两个物体碰撞没有物理效果,只进行碰撞处理)
注意:碰撞和触发响应函数 属于 特殊的生命周期函数 也是通过反射调用
2.物理碰撞检测响应函数
1.碰撞触发接触时会 自动执行这个函数
private void OnCollisionEnter(Collision collision)
{
//Collision类型的 参数 包含了 碰到自己的对象的相关信息
//关键参数
//1.碰撞到的对象碰撞器的信息
//collision.collider
//2.碰撞对象的依附对象(GameObject)
//collision.gameObject
//3.碰撞对象的依附对象的位置信息
//collision.transform
//4.触碰点数相关
//collision.contactCount
//接触点 具体的坐标
//ContactPoint[] pos = collision.contacts;
//只要得到了 碰撞到的对象的 任意一个信息 就可以得到它所有的信息
print(this.name + "被" + collision.gameObject.name + "撞到了");
}
2.碰撞结束分离时 会自动执行的函数
private void OnCollisionExit(Collision collision)
{
print(this.name + "被" + collision.gameObject.name + "结束碰撞了");
}
3.两个物体相互接触摩擦时 会不停的调用该函数
private void OnCollisionStay(Collision collision)
{
print(this.name + "一直在和" + collision.gameObject.name + "接触");
}
3.触发器检测响应函数
1.触发开始的函数 当第一次接触时 会自动调用
private void OnTriggerEnter(Collider other)
{
print(this.name + "被" + other.gameObject.name + "触发了");
}
2.触发结束的函数 当水乳相融的状态结束的时 会调用一次
private void OnTriggerExit(Collider other)
{
print(this.name + "和" + other.gameObject.name + "结束水乳相融的状态了");
}
3.当两个对象 水乳交融的时候 会不停调用
private void OnTriggerStay(Collider other)
{
print(this.name + "正在和" + other.gameObject.name + "水乳相融");
}
4.要明确什么时候会响应函数
- 只要挂载的对象 能和别的物体产生碰撞或者触发 那么对应的这6个函数 就能够被响应
- 6个函数不是说 我都得写 我们一般是根据需求来进行选择书写
- 如果是一个异形物体,刚体在父对象上,如果你想通过子对象上挂脚本检测碰撞是不行的 必须挂载到这个刚体父对象上才行
- 要明确 物理碰撞和触发器响应的区别
5. 碰撞和触发器函数都可以写成虚函数 在子类去重写逻辑
一般会把想要重写的 碰撞和触发函数 写成保护类型的 没有必要写成 public 因为不会自己手动调用
都是Unity 通过反射帮助我们自动调用的
5.刚体加力
1.刚体自带添加力的方法
给刚体加力的目标就是 让其有一个速度 朝向某一个方向移动
1.首先应该获取刚体组件
rigidBody = this.GetComponent<Rigidbody>();
2.添加力
1.相对世界坐标
世界坐标系 z轴正方向加了一个力
rigidBody.AddForce(Vector3.forward*10);
如果想要在 世界坐标系方法中 让对象 相对于自己的面朝向动
rigidBody.AddForce(this.transform.forward * 10);
2.相对本地坐标
本地坐标系 z轴正方向加了一个力
rigidBody.AddRelativeForce(Vector3.forward * 10);
3.添加扭矩力,让其旋转
1.相对世界坐标
世界坐标系 y轴正方向加了一个力
rigidBody.AddTorque(Vector3.up * 10);
2.相对本地坐标
rigidBody.AddRelativeTorque(Vector3.up*10);
4.直接改变速度
这个速度方向 是相对于 世界坐标系
如果要直接通过改变速度 来让其移动 一定要注意这一点
rigidBody.velocity = Vector3.forward * 5;
5.模拟爆炸的效果
参数一:力的大小
参数二:爆炸点
参数三:力的范围
模拟爆炸的力 一定是 所有希望产生爆炸效果影响的对象
都需要得到他们的刚体 来执行这个方法 才能都有效果
rigidBody.AddExplosionForce(100, Vector3.zero,10);
2.力的几种模式
第二个参数 力的模式 主要的作用 就是 计算方式不同而已
由于4种计算方式的不同 最终的移动速度就会不同
rigidBody.AddForce(Vector3.forward * 10, ForceMode.Acceleration);
动量定理
Ft = mv
v = Ft/m
F:力
t:时间
m:质量
v:速度
1.Acceleration
给物体增加一个持续的加速度,忽略其质量
v = Ft/m
F(0,0,10)
t:0.02s
m:默认为1
v = 10*0.02/1 =0.2m/s
每物理帧移动0.2m/s*0.02s=0.004m
2.Force
给物体添加一个持续的力,与物体的质量有关
v = Ft/m
F:(0,0,10)
t:0.02s
m:2kg
v = 10*0.02s/2kg = 0.1m/s
每物理帧移动 0.1m/s*0.02s = 0.002m
3.Impulse
给物体添加一个瞬间的力,与物体的质量有关,忽略时间 默认为1
v = Ft/m
F:(0,0,10)
t:默认为1
m:2kg
v = 10*1/2kg = 5m/s
每物理帧移动 5m/s*0.02s = 0.1m
4.VelocityChange
给物体添加一个瞬时速度,忽略时间、质量
v = Ft/m
F:(0,0,10)
t:默认为1
m:默认为1
v = 10*1/1kg = 10m/s
每物理帧移动 10m/s*0.02s = 0.2m
3.力场脚本
Constant Force
给物体一个持续的力
4.刚体的休眠
获取刚体是否处于休眠状态 如果是休眠状态就唤醒它
if (rigidBody.IsSleeping())
{
//唤醒
rigidBody.WakeUp();
}