游戏中物理引擎用于模拟真实世界物理环境效果,要实现游戏对象的物理行为,Rigidbody(刚体)组件是必不可少的,当挂载该组件之后,物体立刻受到重力等物理效果影响。如果对象身上还挂载着Collider(碰撞)组件,那么该对象还受到碰撞物理效果影响,例如游戏中的被车撞飞
一、Rigidbody组件
Rigidbody组件Unity Manual介绍:Rigidbody
力的效果展示是由Rigidbody组件实现的,只有拥有该组件,物体才会进行力的计算。由Unity Manual我们可知道Rigidbody可实现的功能有哪些
1、组件名称释义
1). Mass:质量,kg,并不是重量mg=N
2). Drag:空气阻力
3). Angular Drag:角旋转阻力
4). Use Gravity:用于确认物体是否受重力影响,如果不勾选该项,则物体不受地心引力影响,不再下坠。但该物体还受其他物理效果影响
5). Is Kinematic:物体不受任何物理效果影响,即使我们通过脚本给它赋予很大的力,也不会移动,只能通过Transform来改变其位置。这通常用于玩家的移动,即不使用力来移动物体,也希望物体进行物理计算的情况,这种运动方式称为“动力学(Kinematic)运动”。
如果该属性设置为true表示该物体运动状态不受外力,碰撞和关节的影响,而只受到动画以及附加在物体上的脚本影响,但是该物体仍然能改变其他物体运动状态,例如游戏中倒下的敌人始终不动 ,就是利用这个不受外力影响的属性,但它也能反馈给其他与他碰撞到的物体一个反作用力,前提是与他碰撞的物体身上要有Rigidbody组件,否则无法产生力的效果(当刚体开启 IsKinematic时,刚体不再参与物理引擎的力计算,如果和他碰撞的物体还没有力,自然就不能计算出碰撞结果)
a、b都有Collider、Rigidbody组件,a开启Is K inematic,b不开启。a撞b,b动;b撞a,b受反作用力动,a不动
6). Constraints:是否约束该物体在X、Y、Z方向的移动或旋转
2、给游戏对象整体施加某个方向的力 AddForce()
Unity Scripting API:Rigidbody.AddForce ForceMode
我们可通过C#脚本方式给物体施加力
代码语言:javascript复制using UnityEngine;
public class CubeAddForce : MonoBehaviour {
private Rigidbody myRigidbody;
void Start () {
myRigidbody = GetComponent<Rigidbody>();
myRigidbody.AddForce(new Vector3(0, 10, 0), ForceMode.Impulse);
}
}
当然,代码中的力的方向我们也可写成
代码语言:javascript复制AddForce(Vector3.up*10,ForceMode.Impulse)
注意:Vector3(0,10,0)要加new,Vector3.up不用
附单位向量代码
代码语言:javascript复制Vector3.up (0,1,0)
Vector3.down (0,-1,0)
Vector3.left (-1,0,0)
Vector3.right (1,0,0)
Vector3.forward (0,0,1)
Vector3.back (0,0,-1)
ForceMode有四个属性:
a、Force:给Rigidbody添加一个可持续的力,受Mass影响,写在Update()等接口中
b、Acceleration:给Rigidbody添加一个可持续的加速度,忽略Mass影响,可在Start()接口
c、Impulse:立即给Rigidbody添加一个冲力,受Mass影响,可在Start()接口
d、VelocityChange:立即给Rigidbody添加速度,忽略Mass影响,写在Update()等接口中
不考虑其他力,仅考虑重力情况下,在Update中添加的力,并不是每帧调用Force会使物体受到的力处于叠加状态,而是遵循牛顿定律,看该力与物体重力关系,相等时则处于平衡状态,其他情况也遵循牛顿定律F-mg=ma
但不受重力影响的力,不断的调用,没有重力的平衡,只能会使物体受到的力叠加地越来越大,直至飞了出去
3、在指定位置施加力 AddForceAtPosition()
代码语言:javascript复制AddForceAtPosition(Vector3 Force,Vector3 Position,ForceMode)
在指定位置施加力实现特定效果。
代码语言:javascript复制myRigidbody.AddForceAtPosition(Vector3.up, new Vector3(1,0,1),ForceMode.Force);
4、实战:模仿手雷爆炸效果 AddExplosionForce()
代码语言:javascript复制AddExplosionForce(float explosionForce,Vector3 explosionPosition,float explosionRadius,float upwardsModifier,ForceMode mode)
float explosionForce:爆炸力
Vector3 explosionPosition:爆炸中心位置
float explosionRadius:爆炸半径
float upwardsModifier:调节爆炸出现的位置,使其看起来像掀起对象。默认从爆炸中心到刚体的质量中心力的方向是线性,如果upwardsModifier是非0值,该方向将通过减去中心点Y轴的值修改。例如:如果该值为2,那么爆炸出现在实际位置中心点2单位以下。使用这个参数,可轻易使爆炸似乎把物体扔到空中,这往往比单纯的外力更具戏剧性效果
ForceMode mode:力模式,同上2描述
思路:爆炸的力位置是从手雷中心开始的,因此力的位置在手雷中心;
爆炸是瞬间发生而不是持续发生的,因此要写在Start接口中();
爆炸力模式应为瞬间力,而不是持续发生,因此要力的模式应该是Impulse
代码语言:javascript复制using UnityEngine;
public class CubeAddForce : MonoBehaviour {
private Rigidbody myRigidbody;
private void Start()
{
myRigidbody = GetComponent<Rigidbody>();
myRigidbody.AddExplosionForce(20, new Vector3(0,0.5f,0), 5, 0, ForceMode.Impulse);
}
}
cube中心是(0,0.5,0),我们设置的爆炸中心也是(0,0.5,0),我们可以看到,运行时在cube中心的爆炸,使其向上飞了出去。当我们将爆炸中心调整到(0,0.51,0)时,爆炸力在cube质心点之上,cube无法移动。同时我们也发现,周围的物体无法受中心cube影响而移动,这是因为力没传到周围物体上。
二、Collider组件
物体运动轨迹改变有两个方式,碰撞或代码。上例没有发生碰撞,力无法传递过去,但没碰撞我们就无法传递力了吗?也可以!通过物理引擎Collider组件的代码,Physics.OverlapSphere(Vector3 position,float radius)方法返回带有Collider的对象,我们只需要遍历他们并给他们的Rigidbody组件施加爆炸位置的力就好了,这当然是要有Collider组件才能实现
注意:组件类型定义变量有GetComponent<>()方法,object型变量不具备该方法
为什么要检测是否拥有Rigidbody组件?因为只有拥有该组件,物体才会进行力的计算。力才有地方去赋值。有Collider组件,才额外进行碰撞计算
代码语言:javascript复制using UnityEngine;
public class CubeAddForce : MonoBehaviour {
private Rigidbody myRigidbody;
void Update()
{
if (Input.GetKeyDown(KeyCode.A))
{
myRigidbody = GetComponent<Rigidbody>();
myRigidbody.AddExplosionForce(20, new Vector3(0, 0.51f, 0), 5, 0, ForceMode.Impulse);
Collider[] colliders = Physics.OverlapSphere(transform.position, 5);
//Collider[] colliders = Physics.OverlapSphere(new Vector3(0,0,0), 5);
//以pointBottom为底部半圆圆心,PointTop为顶部半圆圆心,radius为半径,连接起来构成一个胶囊体
Physics.OverlapCapsule(pointBottom, pointTop, radius, LayerMask);
foreach(Collider obj in colliders)
{
if (obj.GetComponent<Rigidbody>() != null) //只有组件变量才有GetComponent<>()方法,因此object型变量自然不具备该方法了
obj.GetComponent<Rigidbody>().AddExplosionForce(20, new Vector3(0, 0.5f, 0), 5, 2, ForceMode.Impulse);
}
}
}
}
三、Raycast
发射射线,检测一定范围内的物体,返回该物体
代码语言:javascript复制Physics.Raycast(Vector3 origin,Vector3 direction,out RaycastHit hitinfo,float maxDistance)
Vector3 origin:射线起点
Vector3 direction:射线方向
out RaycastHit hitinfo:返回检测距离内检测到的物体
float maxDistance:最大检测距离
此例我们用Physics.Raycast()方法检测10m距离内的物体。我们先定义RaycastHit类型的变量,用于承载该方法检测返回的物体,当我们按下B键,若距离小于5m,则给它施加一个向上的力
代码语言:javascript复制using UnityEngine;
public class CubeAddForce : MonoBehaviour
{
RaycastHit hit;
void Update()
{
if (Input.GetKeyDown(KeyCode.B))
{
if (Physics.Raycast(transform.position, new Vector3(0, -1, 0), out hit, 10f))
{
if (hit.distance < 5)
GetComponent<Rigidbody>().AddForce(Vector3.up*10,ForceMode.Impulse);
}
}
}
}