unity射线碰撞检测及layermask中位运算符使用讲解

一、射线碰撞检测

今天探讨一下unity中射线用法的种类,经过我的查阅发现有好多呀,还有一些和射线类似功能的东东。

1、摄像机创建射线Ray

首先我们创建一个摄像机射线射线,也是常用的简单射线

 //创建射线,从摄像机位置发射射线到鼠标点击位置
 Ray m_Ray = Camera.main.ScreenPointToRay(Input.mousePosition);

然后就是判断射线是否被collider遮挡(这里的collider就是collider组件,不区分该组件是否勾选trigger),首先利用常见的Raycast创建讲解

①、Raycast和RaycastAll方法:

两个方法基本一样,先看Raycast方法:

RaycastHit m_RayHit;//声明存储射线碰撞到的对象信息结构体

if (Physics.Raycast(m_Ray, out m_RayHit, Mathf.Infinity, 1 << 
      LayerMask.NameToLayer("Cube")))
  {
      Debug.Log("Cube射线检测到:" + m_RayHit.collider.gameObject.name);
      Debug.DrawLine(m_Ray.origin, m_RayHit.point);
  }

 上面代码中Physics.Raycast(m_Ray, out m_RayHit, Mathf.Infinity, 1 << LayerMask.NameToLayer("Cube"))返回值类型为bool,就是判断是否碰撞到collider,如果碰撞到返回为真,并且将碰撞到的第一个collider信息存到RaycastHit类型的m_RayHit中,最后一个参数就是本篇文章的第二话题,我们稍后一起讲,先简单理解此处他表示只检测Layer名字为Cube的层。

第二个RaycastAll方法:

RaycastHit[] RayHits = Physics.RaycastAll(m_Ray, Mathf.Infinity, 1 << LayerMask.NameToLayer("Cube"));

if (RayHits.Length > 0)
{
     for (int i = 0; i < RayHits.Length; i++)
     {
         Debug.Log("Cubes检测到:" + RayHits[i].collider.gameObject.name);
         Debug.DrawLine(m_Ray.origin, RayHits[i].point);
     }
}

可以发现它返回的不是bool类型了,而是一个数组,是因为它检测的是这条射线碰撞到的所有collider信息,这就是两者最大的区别。

②、SphereCast方法

其实这里它可以归为一类发射射线方法(例如BoxCast()、CapsuleCast()等等),就是这个的射线不再是一条一维的线了,他可以理解为是一个方向,然后向这个方法投各种形状物体,依照SphereCast就是向某个投掷球形物体,但是有一个不好的就是他不能检测起点到半径之内的物体,也就是说发出射线的时候就已经包含在球半径内的话是不能被检测到的,下面代码样例:

if (Physics.SphereCast(m_Ray, 3,
    out m_RayHit, Mathf.Infinity, 1 << LayerMask.NameToLayer("Cube")))
{
    Debug.Log("Cube球形射线检测到:" + m_RayHit.collider.gameObject.name);
    Debug.DrawLine(m_Ray.origin, m_RayHit.point, Color.red, 3.0f);
}

这里的3就是球形半径,其实这个方法我还没想出来如果不知道原理该如何打印出来这条射线,但是如果想验证它是否真的有“粗”度了,可以利用第一个方法对比就会一目了然了?。

③、OverlapSphere方法

这个方法就完美的填补了上一个SphereCast方法中无法检测半径内的collider物体的遗憾了,它主要检测和球形物体相交或在内部的collider。不过我认为他不算是射线了,有些类似触发器,但是他检测的物体并没有触发器事件那么多的前提条件,他也是只要检测物体有collider组件即可,而且它可不仅仅只有Sphere一个形状哟,还有Box,Capsule等等吧,下面代码样例:

Collider[] HitSpheres = Physics.OverlapSphere(transform.position, 3,
                1 << LayerMask.NameToLayer("Cube"));
if (HitSpheres.Length > 0)
{
   for (int i = 0; i < HitSpheres.Length; i++)
   {
       Debug.Log("Cubes检测到:" + HitSpheres[i].gameObject.name);
   }
}

/// 
/// unity事件
///绘制物体事件
/// 
private void OnDrawGizmos()
{
   Gizmos.color = Color.red;
   //线框绘制
   Gizmos.DrawWireSphere(transform.position, 3);
}

 这个方法是直接返回collider数组,3同样表示球形半径,下面的OnDrawGizmos函数是unity自带的一个绘制物体函数,主要为了便于观察。

二、利用其他物体发射射线

此处和前面类似不多解释,先看代码:

根据物体创建射线。
Vector3 fwd = transform.TransformDirection(Vector3.forward);//方向
if (Physics.Raycast(transform.position, fwd, out m_RayHit))
{
     Debug.Log("物体自身发射射线:" + m_RayHit.collider.gameObject.name);
     Debug.DrawLine(transform.position, m_RayHit.point);
}

 直接利用Raycast方法,设定起点和方向即可,省去了创建Ray射线步骤。

二、layermask中位运算符

本节参考链接:https://www.cnblogs.com/leeplogs/p/9133824.html

首先说一下位运算符

按位运算符:与(&)、非(~)、或(|)、异或(^)、<<(左移)、>>(右移)。位运算符主要用来对二进制位进行操作。

与运算符:只有两个位都是1,结果才是1;

或运算符:只要两个位有一个是1,结果就是1;

非运算符:如果位为0,结果是1,如果位为1,结果是0;

异或运算符:两个操作数的位中,相同则结果为0,不同则结果为1;

左移运算符<<:左移表示乘以2,左移多少位表示乘以2的几次幂;

右移运算符>>:移动多少位表示除以2的几次幂。

 

Unity是用 int32来表示32个Layer层,int32用二进制来表示一共有32位。

0000 0000 0000 0000 0000 0000 0000 0000

31                    0

eg:

(1)Physics.Raycast(m_Ray, out m_RayHit, Mathf.Infinity, 1 << 8) ----开启Layer8

其中 <<左边的 1表示有[开启],0表示没有该layer[忽略] 。右边的2表示左移2位即是 layer2层的位置。

(2)Physics.RaycastAll(m_Ray, Mathf.Infinity, 1 << 9|1<<10) ----开启layer 9和layer 10

(3)Physics.RaycastAll(m_Ray, Mathf.Infinity, 1 << 9|0<<10) ----开启Layer9 并关闭 Layer10

(4)Physics.RaycastAll(m_Ray, Mathf.Infinity, ~(1 << 9)) ----关闭Layer9层,变0 按位取反 ~
上面列举了我在unity经常使用的一些位运算符,其他的含义已经为大家列举出来了,可以时情况而应用

你可能感兴趣的:(unity,C#)