Unity 物理系统 -- 射线简介

766 阅读3分钟

「这是我参与11月更文挑战的第18天,活动详情查看:2021最后一次更文挑战

 Unity 物理系统 -- 射线简介

有关射线(Ray)的几个结构体(类):

  • Physics (物理类):RayCast()用来发射一条射线;
  • Ray(Struct):表示射线本身的对象
  • RaycastHit(struct):射线和其他碰撞器的碰撞信息

绘制射线函数

  • Debug.DrawLine(transform.position,Vector3.forward * 10,Color.blue,10f);
  • Debug.DrawRay(transform.position,Vector3.left * 10,Color.red);

注:

  1. 第一个参数是绘制出来的位置
  2. 第二个参数是绘制出来的点,默认是1,可以乘一个float类型的数值来增加其射线长度
  3. 第三个参数是颜色
  4. 第四个参数是射线区域,如果改变了射线方向,则射线会形成一个区域,为float类型,值越大,停留的时间越长.

射线检测

射线检测的相关参数概念:

  • RaycastHit hit:光线投射碰撞(此变量用于存储此射线碰到了哪些物体的信息)
  • Camera.main.ScreenPointToRay(位置):屏幕位置发射线:返回一条射线从摄像机通过一个屏幕点

注:

  1. 产生的射线是在世界空间中,从相机的近裁剪面开始并穿过屏幕position(x,y)像素坐标(position.z被忽略)。
  2. 屏幕空间以像素定义。屏幕的左下为(0,0);右上是(pixelWidth,pixelHeight)。

相关API:

  1. Ray Camera.main.ScreenPointToRay(Vector3 pos) 返回一条射线Ray从摄像机到屏幕指定一个点
  2. Ray 射线类
  3. RaycastHit 光线投射碰撞信息
  4. bool Physics.Raycast注意:如果从一个球型体的内部到外部用光线投射,返回为假。

参数理解:

  • origin : 在世界坐标中射线的起始点
  • direction: 射线的方向
  • distance: 射线的长度
  • hit: 使用c#中out关键字传入一个空的碰撞信息类,然后碰撞后赋值。可以得到碰撞物体的transform,rigidbody,point等信息。
  • layerMask: 只选定Layermask层内的碰撞器,其它层内碰撞器忽略。 选择性的碰撞过滤物体。可以在TagManager中编辑tag和Layer。然后设置物体的Layer层级,在摄像机中设置camera.cullingmask,可以控制摄像机的渲染层级,用在射线上,可以控制射线碰撞什么,不碰撞什么。
  • 返回布尔类型,当光线投射与任何碰撞器交叉时为真,否则为假。注意:如果从一个球型体的内部到外部用光线投射,返回为假。

射线的5个参数:

RaycastHit[] RaycastAll(Ray ray, float distance, int layerMask)

投射一条光线并返回所有碰撞,也就是投射光线并返回一个RaycastHit[]结构体。

  • Physics.Raycast(射线 ray, 光线投射碰撞到的物体 out hit, 射线长度 distance);
  • Physics.Raycast(位置 position, 方向 forward, 光线投射碰撞到的物体 out hit, 射线长度 distance);
  • Physics.Raycast(位置 position, 方向 forward, 光线投射碰撞到的物体 out hit, 射线长度 distance, 遮罩过滤层 layerMask 1<<8);

注:

  1. 第一个参数是射线的起点
  2. 第二个参数是射线的方向
  3. 第三个参数是碰撞的信息
  4. 第四个参数是射线的长度
  5. 第五个参数是遮罩过滤层(二进制的形式写的,所以我们用的时候需要使用简单的左移运算(<<)
public class RayDemo : MonoBehaviour 
{

    //创建一个平面,当点击这个平面的某一点时,从摄像机发射一个子弹打向这个点.
    Ray ray;
    RaycastHit rh;

	void Start ()
        {
            //ray = new Ray(Vector3.zero,Vector3.forward);   //创建一条射线,

            //Physics.Raycast(Vector3.zero, Vector3.forward);
            //if(Physics.Raycast(ray,out rh, 0.5f))
            //{
            //    print(rh.point);   //碰撞点
            //}
	}

    void Update()
    {
        ray = Camera.main.ScreenPointToRay(Input.mousePosition);   //鼠标位置发射线

        if (Input.GetMouseButtonDown(0))                     //按下鼠标左键
        {
            if (Physics.Raycast(ray, out rh, 10f))           //发射一个射线
            {
                Destroy(rh.transform.gameObject);            //射线碰到物体消失
                Debug.Log(rh.point);                         //打印碰撞的点
            }
        }
    }
}

通过层对射线进行设定:

public class Ray1Demo : MonoBehaviour
{
    GameObject go;
    
    void Start()
    {
        go = GameObject.Find("Cube2");
    }
    
    void Update()
    {
        go.transform.Rotate(new Vector3(0, 1, 0));
        RaycastHit hit;
        Vector3 fwd = transform.TransformDirection(Vector3.forward);
        
        if (Physics.Raycast(transform.position, fwd, out hit, 100, 1 << 8))
        {	
            //1位移8,这个参数表示只能检测到参数中的层		
            //射线碰撞层级为8,其他层级忽略。
            Destroy(hit.collider.gameObject);
        }
    }
}

/*
注:
  1 << 10 打开第10的层。
  ~(1 << 10) 打开除了第10之外的层。默认层不算,要手动添加的才可以
  (1 << 10) | (1 << 8) 打开第10和第8的层。
		//射线碰撞层级为8,其他层级忽略。
            Destroy(hit.collider.gameObject);
        }
    }
}

注:
  1 << 10 打开第10的层。
  ~(1 << 10) 打开除了第10之外的层。默认层不算,要手动添加的才可以
  (1 << 10) | (1 << 8) 打开第10和第8的层。

*/