什么是射线检测

解决以下问题:

  • 鼠标选择场景上一物体
  • FPS射击游戏(无弹道-不产生实际的子弹对象进行移动)
  • 等需要判断一条线和物体的碰撞情况
    它可以在指定点发射一个指定方向的射线
    判断该射线与哪些碰撞器相交,得到对应对象

射线对象

单独的射线对于我们来说没有实际的意义,我们需要用它结合物理系统进行射线碰撞判断

3D世界中的射线

  • 参数一:起点
  • 参数二:方向
1
Ray r = new Ray(Vector3.right, Vector3.forward);

摄像机发射出的射线

屏幕位置 为起点
摄像机视口方向 为方向

1
Ray r2 = Camera.main.ScreenPointToRay(Input.mousePosition);

碰撞检测 API

射线检测也是瞬时
执行代码时进行一次射线检测

最原始的射线检测

准备一条射线

1
Ray r = new Ray(Vector3.zero, Vector3.forward);

Physics.Raycast()

  • 参数一:射线
  • 参数二: 检测的最大距离 超出这个距离不检测
  • 参数三:检测指定层级(不填检测所有层)
  • 参数四:是否忽略触发器 UseGlobal-使用全局设置 Collide-检测触发器
    Ignore-忽略触发器 不填使用UseGlobal
  • 返回值:bool 当碰撞到对象时 返回 true 没有 返回false
1
2
3
4
5
if (Physics.Raycast(r, 1000, 1 << LayerMask.NameToLayer("Monster"), 
QueryTriggerInteraction.UseGlobal))
{
print("碰撞到了对象");
}

还有一种重载 不用传入 射线 直接传入起点 和 方向 也可以用于判断

1
2
3
4
5
if (Physics.Raycast(Vector3.zero, Vector3.forward, 1000, 
1 << LayerMask.NameToLayer("Monster"),QueryTriggerInteraction.UseGlobal))
{
print("碰撞到了对象");
}

获取相交的单个物体信息

物体信息类
通过RaycastHit类 我们得到得到 碰撞到的对象信息
还可以得到一些 碰撞的点 距离 法线等等的信息

1
RaycastHit hitInfo;
  • 参数一:射线
  • 参数二:RaycastHit是结构体 是值类型 Unity会通过out
    在函数内部处理后 得到碰撞数据后返回到该参数中
  • 参数三:距离
  • 参数四:检测指定层级
  • 参数五:是否忽略触发器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
if( Physics.Raycast(r, out hitInfo, 1000, 1<<LayerMask.NameToLayer("Monster"), 
QueryTriggerInteraction.UseGlobal) )
{
//碰撞器信息
print("碰撞到物体的名字" + hitInfo.collider.gameObject.name);
//碰撞到的点
print(hitInfo.point);
//法线信息
print(hitInfo.normal);
//得到碰撞到对象的位置
print(hitInfo.transform.position);
//得到碰撞到对象 离自己的距离
print(hitInfo.distance);
}

同理 还有一种重载 不用传入 射线 直接传入起点 和 方向 也可以用于判断

获取相交的多个物体

Physics.RaycastAll()

可以得到碰撞到的多个对象,如果没有 就是容量为0的数组

  • 参数一:射线
  • 参数二:距离
  • 参数三:检测指定层级
  • 参数四:是否忽略触发器
1
2
3
4
5
6
RaycastHit[] hits = Physics.RaycastAll(r, 1000, 1 << LayerMask.NameToLayer("Monster"),
QueryTriggerInteraction.UseGlobal);
for (int i = 0; i < hits.Length; i++)
{
print("碰到的所有物体 名字分别是" + hits[i].collider.gameObject.name);
}

还有一种NonAlloc型的函数 返回的碰撞的数量 通过out得到数据
Physics.RaycastNonAlloc()

1
2
3
4
RaycastHit[] hits;
if(Physics.RaycastNonAlloc(r, hits, 1000, 1 << LayerMask.NameToLayer("Monster"),
QueryTriggerInteraction.UseGlobal) > 0 ){
}

使用时注意的问题

注意
距离层级两个参数 都是int类型
当我们传入参数时 一定要明确传入的参数代表的是距离还是层级