U2L13-2——物理系统之射线检测
U2L13-2——物理系统之射线检测
本章代码关键字
1 | Ray //射线类,根据起点和方向确定射线,用于接下来的检测函数 |
射线检测
物理系统中,目前我们学习的物体相交判断有:
- 碰撞检测函数 —— 必备条件:1、刚体,2、碰撞器
- 范围检测 —— 必备条件:碰撞器
如果想要做这样的碰撞检测
- 鼠标选择场景上一物体
- FPS射击游戏(无弹道 - 不产生实际的子弹对象进行移动)
等等 需要判断一条线和物体的碰撞情况
射线检测 就是来解决这些问题的,它可以在指定点发射一个指定方向的射线
判断该射线与哪些碰撞器相交,得到对应对象
射线对象
3D世界中的射线
注意:单独的射线对于我们来说,没有任何实际的意义,我们需要用它来结合物理系统进行射线判断
假设有一条 起点为坐标(1, 0, 0) 方向为世界坐标Z轴正方向的射线
注意:理解参数含义
- 参数一:起点
- 参数二:方向 (一定记住 不是两点决定射线方向,第二个参数直接就代表 方向向量)
1 | Ray r = new Ray(Vector3.right, Vector3.forward); |
目前只是申明了一个射线对象,对于我们来说,没有任何用处
Ray中的参数
1 | print(r.origin); //起点 |
摄像机发射出的射线
得到一条从屏幕位置作为起点,以摄像机视口方向为方向的射线
1 | Ray r2 = Camera.main.ScreenPointToRay(Input.mousePosition); |
射线的碰撞检测函数
Physics类中提供了很多进行射线检测的静态函数
他们有很多种重载类型我们只需要掌握核心的几个函数其它函数自然就明白什么意思了
注意:射线检测也是瞬时的,执行代码时进行一次射线检测
注意!距离、层级两个参数,如果都是int类型,可能会出现混淆问题****所以当我们传入参数时,一定要明确传入的参数代表的是距离还是层级!!! 参数里,距离在前,层级在后!
例如:下面的内容就是错误的
1 | if (Physics.Raycast(r3, 1 << LayerMask.NameToLayer("Monster")) //这个参数是错误的!!! |
最原始的射线检测
准备一条射线
1 | Ray r3 = new Ray(Vector3.zero, Vector3.forward); |
进行射线检测,如果碰撞到对象 返回Ture
- 参数一:射线对象
- 参数二:检测的最大距离,超过这个距离不检测
- 参数三:检测指定层级(不填检测所有层)(注意!有特殊的填入规则!)
- 参数四:是否忽略触发器
UseGlobal
-使用全局设置Collide
-检测触发器Ignore
-忽略触发器 不填使用UseGlobal
- 返回值:
bool
,当碰撞到对象时,返回true
,否则,返回false
1 | if (Physics.Raycast(r3, 1000, 1 << LayerMask.NameToLayer("Monster"), QueryTriggerInteraction.UseGlobal)) |
还有一种重载,不用射线,直接传入起点和方向 也可以用于判断
就是把 第一个参数射线 变成了 射线的两个参数:起点和方向
1 | if (Physics.Raycast(Vector3.zero, Vector3.forward, 1000, 1 << LayerMask.NameToLayer("Monster"), QueryTriggerInteraction.UseGlobal)) |
但是只有射线检测是不能直接得到被击中的对象的信息的,我们还需要RaycastHit类来装载物体信息
获取相交的单个物体信息
物体信息类 RaycastHit
RaycastHit
该类 对于我们的意义
它不仅可以得到我们碰撞到的对象信息
还可以得到一些 碰撞的点 距离 法线 等等的信息
使用这些信息可以用来创建诸如弹痕之类的东西
1 | RaycastHit hitInfo; |
- 参数一:射线对象
- 参数二:
RaycastHit
结构体 是值类型 Unity会通过 out
关键字 在函数内部处理后 得到碰撞数据返回到该参数中 - 参数三:检测的最大距离,超过这个距离不检测
- 参数四:检测指定层级(不填检测所有层)(注意!有特殊的填入规则!)
- 参数五:是否忽略触发器
UseGlobal
-使用全局设置Collide
-检测触发器Ignore
-忽略触发器 不填使用UseGlobal
1 | if (Physics.Raycast(r3, out hitInfo, 1000, 1 << LayerMask.NameToLayer("Monster"), QueryTriggerInteraction.UseGlobal)) |
同样的,还有一种重载,不用射线,直接传入起点和方向 也可以用于判断
就是把 第一个参数射线 变成了 射线的两个参数:起点和方向
1 | if (Physics.Raycast(Vector3.zero, |
获取相交的多个物体信息
可以得到碰撞到的多个对象
如果没有就是容量为0的数组
- 参数一:射线对象
- 参数二:检测的最大距离,超过这个距离不检测
- 参数三:检测指定层级(不填检测所有层)(注意!有特殊的填入规则!)
- 参数四:是否忽略触发器
UseGlobal
-使用全局设置Collide
-检测触发器Ignore
-忽略触发器 不填使用UseGlobal
注意,数组的顺序是,先进来的在开头,后面的在结尾
1 | RaycastHit[] hits = Physics.RaycastAll(r3, 1000, 1 << LayerMask.NameToLayer("Monster"), QueryTriggerInteraction.UseGlobal); |
同样的,还有一种重载,不用射线,直接传入起点和方向 也可以用于判断
就是把 第一个参数射线 变成了 射线的两个参数:起点和方向
1 | hits = Physics.RaycastAll(Vector3.zero, |
返回碰撞的数量
返回碰撞的数量,通过out
得到数据
1 | if (Physics.RaycastNonAlloc(r3, |