设为首页收藏本站
查看: 844|回复: 0

Cha10.0丨物理引擎Rigidbody组件、Collider组件、Raycast

[复制链接]

该用户从未签到

17

主题

19

帖子

447

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
447
橙子va 发表于 2018-5-26 10:57:21 8440 | 显示全部楼层 |阅读模式

游戏中物理引擎用于模拟真实世界物理环境效果,要实现游戏对象的物理行为,Rigidbody(刚体)组件是必不可少的,当挂载该组件之后,物体立刻受到重力等物理效果影响。如果对象身上还挂载着Collider(碰撞)组件,那么该对象还受到碰撞物理效果影响,例如游戏中的被车撞飞


一、Rigidbody组件

Rigidbody组件Unity Manual介绍:Rigidbody

力的效果展示是由Rigidbody组件实现的,只有拥有该组件,物体才会进行力的计算。由Unity Manual我们可知道Rigidbody可实现的功能有哪些


1、组件名称释义

Inspector-Rigidbody.png

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不动

0521-01.gif

6). Constraints:是否约束该物体在X、Y、Z方向的移动或旋转


2、给游戏对象整体施加某个方向的力 AddForce()Unity Scripting API:Rigidbody.AddForceForceMode

我们可通过C#脚本方式给物体施加力

  1. using UnityEngine;

  2. public class CubeAddForce : MonoBehaviour {

  3.     private Rigidbody myRigidbody;

  4.         void Start () {
  5.         myRigidbody = GetComponent<Rigidbody>();
  6.         myRigidbody.AddForce(new Vector3(0, 10, 0), ForceMode.Impulse);
  7.         }
  8. }
复制代码

0521-02.gif

当然,代码中的力的方向我们也可写成

  1. AddForce(Vector3.up*10,ForceMode.Impulse)
复制代码

注意:Vector3(0,10,0)要加new,Vector3.up不用

0522_01.png

附单位向量代码

  1. Vector3.up      (0,1,0)
  2. Vector3.down    (0,-1,0)
  3. Vector3.left    (-1,0,0)
  4. Vector3.right   (1,0,0)
  5. Vector3.forward (0,0,1)
  6. 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()
  1. AddForceAtPosition(Vector3 Force,Vector3  Position,ForceMode)
复制代码

在指定位置施加力实现特定效果。

  1. myRigidbody.AddForceAtPosition(Vector3.up, new Vector3(1,0,1),ForceMode.Force);
复制代码


4、实战:模仿手雷爆炸效果 AddExplosionForce()
  1. 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

  1. using UnityEngine;

  2. public class CubeAddForce : MonoBehaviour {

  3.     private Rigidbody myRigidbody;

  4.     private void Start()
  5.     {
  6.         myRigidbody = GetComponent<Rigidbody>();
  7.         myRigidbody.AddExplosionForce(20, new Vector3(0,0.5f,0), 5, 0, ForceMode.Impulse);
  8.     }
  9. }
复制代码
0522-01.gif

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组件,才额外进行碰撞计算

  1. using UnityEngine;

  2. public class CubeAddForce : MonoBehaviour {

  3.     private Rigidbody myRigidbody;

  4.     void Update()
  5.     {
  6.         if (Input.GetKeyDown(KeyCode.A))
  7.         {
  8.             myRigidbody = GetComponent<Rigidbody>();
  9.             myRigidbody.AddExplosionForce(20, new Vector3(0, 0.51f, 0), 5, 0, ForceMode.Impulse);

  10.             Collider[] colliders = Physics.OverlapSphere(transform.position, 5);
  11.           //Collider[] colliders = Physics.OverlapSphere(new Vector3(0,0,0), 5);

  12.         foreach(Collider obj in colliders)
  13.             {
  14.                 if (obj.GetComponent<Rigidbody>() != null)   //只有组件变量才有GetComponent<>()方法,因此object型变量自然不具备该方法了
  15.                     obj.GetComponent<Rigidbody>().AddExplosionForce(20, new Vector3(0, 0.5f, 0), 5, 2, ForceMode.Impulse);
  16.             }
  17.         }
  18.     }
  19. }
复制代码

0522-02.gif


三、Raycast

发射射线,检测一定范围内的物体,返回该物体

  1. 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,则给它施加一个向上的力

  1. using UnityEngine;

  2. public class CubeAddForce : MonoBehaviour
  3. {
  4.     RaycastHit hit;

  5.     void Update()
  6.     {
  7.         if (Input.GetKeyDown(KeyCode.B))
  8.         {
  9.             if (Physics.Raycast(transform.position, new Vector3(0, -1, 0), out hit, 10f))
  10.             {
  11.                 if (hit.distance < 5)
  12.                     GetComponent<Rigidbody>().AddForce(Vector3.up*10,ForceMode.Impulse);
  13.             }
  14.         }
  15.     }
  16. }
复制代码

0526-01.gif



回复

使用道具 举报

0条回复
跳转到指定楼层

发表回复

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|赛隆网 ( 粤ICP备16067842号 )  

Copyright 2013 -̳ Ȩ All Rights Reserved.

Powered by Cylonspace ; All Rights Reserved.

QQ|Archiver|手机版|小黑屋|赛隆网 ( 粤ICP备16067842号 )  

GMT+8, 2018-10-21 21:20 , Processed in 0.134681 second(s), 27 queries.

快速回复 返回顶部 返回列表