七彩极 发表于 2022-8-30 10:13

Unity的Physics.Raycast()方法,为什么指定层遮罩后还会 ...

错误代码

public class ChoiceWeapon : MonoBehaviour
{
    Ray ray;
    private void Update()
    {
      //从摄像机到鼠标指向位置发射射线
      Vector2 mousePos = Input.mousePosition;
      ray = Camera.main.ScreenPointToRay(mousePos);
      TestRay();
    }
    private void TestRay()
    {
      RaycastHit hitInfo;
      //下面的if,判断射线是否检测碰撞到Enemy层;
      if(Physics.Raycast(ray, out hitInfo, LayerMask.GetMask("Enemy")))
      {
            Debug.Log(hitInfo.transform.name);
      }
    }
}
上述代码,妄想通过射线,检测是否碰撞Enemy层的物体,然而在实际运行过程中,会发现射线碰撞所有物体的时候,都会执行if内的代码,即使不是Enemy层,也会被检测到。
不使用GetMask()方法,用左移运算符也是如此;
if(Physics.Raycast(ray, out hitInfo,1<<2))
且当第三个参数值较小的时候,无法检测到任何层的物体。
原因

通过检查Raycast()方法的重载可以发现,并没有bool Physics.Raycast(Ray ray,out RaycastHit hitInfo, int layerMask)的重载。
只有以下两种重载形式:




当我们使用Physics.Raycast(ray,out hitInfo, LayerMask.GetMask("Enemy"))时,其实加载的是上面的那个重载,只有三个参数的重载。
而LayerMask.GetMask("Enemy"))被当做了maxDistance,这里有些人可能会疑惑,简单解释一下,层是用int的不同位来表示的。


如上图,Default就是1,TransparentFX就是1<<1,IgnoreRaycast就是1<<2,依此类推,Enemy就是1<<6。
LayerMask.GetMask("Enemy")等价于1<<6;
所以此时第三个参数是int类型,并没有报错。我们使用的层遮罩,就被当成了一个射线的最远距离,这也是为什么,当层遮罩的值很小时,无法检测到任何物体,因为指定的射线最远距离太短了,碰不到任何物体。
解决方案

而我们想要使用层遮罩的话,就要使用下面这个重载。


同时指定最远距离和层遮罩。
改动后的if代码:
      if(Physics.Raycast(ray, out hitInfo, Mathf.Infinity, LayerMask.GetMask("Enemy")))
      {
            //......
      }
Mathf.Infinity是正无穷大。
改完后,就可以正常的检测碰撞Enemy层物体了。
页: [1]
查看完整版本: Unity的Physics.Raycast()方法,为什么指定层遮罩后还会 ...