unity射线使用方法详解

目录

射线的编程方法

射线的碰撞信息

穿过多个物体的射线 

获取图层的方法 

区域覆盖型射线(Overlap)

射线的调试方法 


射线在游戏开发中,应用非常广泛,所以掌握射线非常重要。

列如:判断角色是否着地,可以向角色脚下发射射线,判断是否接触地面。

注意:各种射线检测都是以物理系统为基础的。射线需要与碰撞体和触发器配合才能发挥出作用。

射线与视线一样会被障碍物阻挡并且射线不仅可以有长度,还可以有粗细和形状,列如球形射线,盒子射线和胶囊体射线。方法都大同小异。

射线的编程方法

常用的直线射线类型用类型Ray表示,Ray包含了起点origin跟方向direction的定义,起点和方向都用Vector3类型表示,前者是一个坐标,后者是一个表示方向的向量。

Vector3 origin = transform.position;
Vector3 direction = Vector3.down;
Ray ray = new Ray(origin, direction);

在游戏中发射一条射线,最常用的是physics.Raycast()和physics.RaycastAll(),前者只能检测一个碰撞体而被返回,后者可以一起检测多个碰撞体。我们先讲讲Raycast(),常用的重载方法如下


 bool raycast =Physics.Raycast(ray.origin,ray.direction,out RaycastHit hitInfo,float maxDistance,int layerMask);

这里有五个参数,第一个是发射起点,第二个是发射方向,第三个是发射距离,第四个是射线碰撞信息,第五个是发射图层,只检测指定图层,而忽略其他图层,最后返回值bool是是否击中某个碰撞体或者触发器。其中,前两个参数是必须,后三个参数根据我们的需要可加可不加。

射线的碰撞信息

我们再重点讲讲第三个参数RaycastHit,若没有这个参数,我们的返回值仅仅只是“是否碰到了物体”,而无法确定碰撞点在哪,也不知道碰撞体是哪一个。射线检测其实有着非常丰富的碰撞信息,如可以获得其碰撞坐标,信息,以及法线。这些丰富的信息都被保存在RaycastHit结构体中。

综合用法演示如下:

    //声明变量,用于保存信息
    RaycastHit hitInfo;
    //发射射线,起点是当前物体位置,方向是世界前方
    if(Physics.Raycast(transform.position,Vector3.forward,out hitInfo))
    {
        //如果碰到物体,运行此处,返回的是bOOl值
        //获取碰撞点坐标
        Vector3 point = hitInfo.point;
        //获取对方碰撞体组件
        Collider coll = hitInfo.collider;
        //获取对方的Transgorm组件
        Transform trans = hitInfo.transform;
        //获取对方的物体名称
        string name = hitInfo.collider.name;
        //获取碰撞点的法线向量
        Vector3 normal = hitInfo.normal;
    }

注意,2D游戏跟3D游戏获取碰撞体的方式有些不一样,具体对比如下

    //声明变量,将碰撞信息直接赋值给变量
    RaycastHit2D hitInfo=Physics2D.Raycast(transform.position,Vector3.forward);
    //发射射线,起点是当前物体位置,方向是世界前方
    if(hitInfo.collider != null)
    {
        //如果检测的碰撞体不为空,运行此处。
        //获取碰撞点坐标
        Vector3 point = hitInfo.point;
        //获取对方碰撞体组件
        Collider coll = hitInfo.collider;
        //获取对方的Transgorm组件
        Transform trans = hitInfo.transform;
        //获取对方的物体名称
        string name = hitInfo.collider.name;
        //获取碰撞点的法线向量
        Vector3 normal = hitInfo.normal;
    }

穿过多个物体的射线 

前面我们提到了Raycast()跟RaycastAll的区别,,区别是前者只能检测一个碰撞体便返回,后者是能可以获取到射线沿途碰到的所有信息(在指定图层内)。我们以2D为例,差异看图

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5a2m5Lmg5L2_5oiR5b-r5LmQMTM=,size_20,color_FFFFFF,t_70,g_se,x_16

如图,圆形物体发射的射线被绿色碰撞体阻挡,无法到达蓝色碰撞体,所以此时射线只能检测绿色图层,但不能检测蓝色碰撞体,那我们怎么能即检测绿色碰撞体又能检测蓝色碰撞体。这时就需要我们使用Physics,RaycastAll(),该函数的返回值是RaycastHit数组。重载方式如下:

RaycastHit[] hit = Physics.RaycastAll(Vector3 origin,Vector3 direction,float maxDistance,int LayerMask);

利用此函数,我们便可以实现同时检测绿色,蓝色两个碰撞体,效果如下

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5a2m5Lmg5L2_5oiR5b-r5LmQMTM=,size_20,color_FFFFFF,t_70,g_se,x_16 例子代码,仅供参考

RaycastHit2D[] hitInfo = Physics2D.RaycastAll(ray.origin,ray.direction,10f,LayerMask.GetMask("ground","war"));
for(i=0;i<hitInfo.Length;i++)
{
    Debug.DrawLine( ray.origin,hitInfo[i].point ,Color.red);
    Debug.Log(hitInfo[i].collider.name);
}

获取图层的方法 

其中介绍一一个小知识,这里获取图层的方法是LayerMask.GetMask(),这里可获得一个图层或者多个图层

例如获得Ground,player,obstacle者三个层,代码如下

int mask = layerMask.GetMask("ground","player","obstacle");

区域覆盖型射线(Overlap)

有时候需要检测一个空间的范围,例如炸弹爆炸时,范围十米之内的物体都会受到波及,那么这里需要的不是一条射线,而是一个半径为10米的球形区域。物理系统也提供了这类函数,它们均已Physics。Overlap开头,这里以球形区域为例:

Collider[] collider = overlapSphere(Vector3 position,float radius,int LayerMask);

第一个参数是位置,第二个参数是范围距离,第三个是图层,且该返回值是collider。

射线的调试方法 

利用Debug调试

在游戏开发中,射线的调试方法非常重要,可以将看不见的射线以可视化的形式表现出来,方便我们查看数据是否正确。这个方法是使用Debug.DrawLine()函数和Debug.DrawRay().

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5a2m5Lmg5L2_5oiR5b-r5LmQMTM=,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5a2m5Lmg5L2_5oiR5b-r5LmQMTM=,size_20,color_FFFFFF,t_70,g_se,x_16    效果图可以看上面,都有涉及使用到。需要说明的是在默认的情况下,该辅助线仅在编辑器的场景窗口可见,如果要在game窗口看到,则需要单机Game窗口右上角的Gizmos开关。

 利用Gizmos

调用OnDrawGizmos()函数或OnDrawGizmosSelected,它们同样都可以用来绘制辅助图标。区别在于

函数OnDrawGizmos()在程序一运行就执行,之后每帧都在执行,

函数OnDrawGizmosSelected()在鼠标点击到脚本挂载的物体的身上的时候运行,不管有多少父类对象,它都会执行。

这里推荐使用OnDrawGizmosSelected()

范例如下

  private void OnDrawGizmosSelected()
    {
      
       Gizmos.DrawLine(Vector3 from, Vector3 to);
       Gizmos.DrawRay((Vector3 from, Vector3 direction);
    }

可在scence窗口查看辅助线,同样想在game窗口可以看到,则需要单机Game窗口右上角的Gizmos开关。

猜你喜欢

转载自blog.csdn.net/maojiaoliang/article/details/124049050