UnityVR--组件4--Ray/Raycast/Linecast/OverlapSphere

目录

Ray/Raycast/Linecast//OverlapSphere简介

Ray类

Physics.Raycast方法

应用1:实现鼠标点击出射线并检测物体

应用2:实现鼠标点击拖拽物体

Physics.Linecast和Physics.OverlapSphere

应用3:进入范围时触发攻击


Ray/Raycast/Linecast//OverlapSphere简介

  射线(Ray类)在三维世界中从一个点沿一个方向发射的一条无限长的线,它的主要应用,例如:

  1. 在之前的文章unity oculus手柄射线中,使用从手柄射出的射线去点击VR中的UI按钮;

  2. 在普通3D游戏中,用鼠标或触摸的方式去拖拽、点击物体(构建一条从屏幕向物体的射线);

  3. 其他:射击中的瞄准器、从某一物体出发划出一个范围、等等……

  Raycast是物理系统中的一个方法,是用射线的形式检测在射线通过的道路上是否有碰撞体存在,就像以前做过的激光门伤害小游戏一样。同样类型的还有RaycastAll

  LinecastOverlapSphere是物理系统中的线性检测和球型检测,检测在线性或球形范围内是否有碰撞体,Linecast返回布尔值,OverlapSphere返回一个数组。

Ray类

  射线的两个重要参数就是起点(origin)和方向(direction)。Ray类的带参构造是public Ray(Vector3 origin, Vector3 direction)  ,也就是我们在创建一条射线时需要传起点和方向两个参数。另外,这个类中只有一个方法GetPoint(),用于返回一个射线上的点。方法定义如下:

public Ray(Vector3 origin, Vector3 direction)
        {
            m_Origin = origin;
            m_Direction = direction.normalized;
        }

public Vector3 GetPoint(float distance)
        {
            return m_Origin + m_Direction * distance;
        }

Physics.Raycast方法

  作用:在场景中发射一条射线,检测其是否与碰撞器碰撞。

  定义:(居然有15个重载)语法如下

public static bool Raycast(Ray ray)

public static bool Raycast(Vector3 origin, Vector3 direction)

public static bool Raycast(Ray ray, out RaycastHit hitInfo, float maxDistance)

//激光门中用过:
public static bool Raycast(Vector3 origin, Vector3 direction, out RaycastHit hitInfo, float maxDistance, int layerMask)

  重要参数说明:

参数作用
origin射线起点坐标(世界),Vector3
direction射线方向,Vector3
distance射线长度,float
layermask选定的检测层(其他层不检测),int
hitInfo检测到的第一个对象信息,RaycastHit类

  其中的hitInfo参数是RaycastHit类,用于存储被检测到的第一个对象的信息,包括:transform、rigidbody、collider、distance(从射线起点到与碰撞对象的交点的距离 )、point(交点的坐标)、normal(射线入平面的法向量)

Physics.Line

应用1:实现鼠标点击出射线并检测物体

  在应用中,我们经常会有用鼠标或者手柄去点击并拾取物体的需求,那就需要从屏幕(也就是Camera)或者手柄的位置发出一条射线到物体。下面就设置了捕捉鼠标左键的点击,并从主camera发射一条射线,方向是鼠标点击的位置,再用RaycastHit检测是否射到了敌人(敌人加入Enemy层)。update()中的代码如下:

Update()
{
  if(Input.GetMouseButtonDown(0))
  {//如果有鼠标左键的点击
     //定义一个射线ray,设置射线从主摄像机到鼠标位置
     Ray ray=Camera.main.ScreenPointToRay(Input.mousePosition);
     Tools.DrawLine(transform, ray.origin, ray.direction, Color.white, 0.05f);//用Tools工具中的DrawLine方法将这条线画出来
     //测试Raycast
     Physics.Raycast(ray, out RaycastHit hit, 100, LayerMask.GetMask("Enemy","UI"));
     if(hit.collider != null)
     {
       Debug.LogError("打中敌人了!");
     }
  }
}

  效果如下图,可以看到每次射线点到红色敌人时,左下角都会有文字提示。

 应用2:实现鼠标点击拖拽物体

  实现过程:

  第一步:从Camera向鼠标点击方向做一条射线(和应用1一样);

  第二步:射线检测被拖拽物体;修改一下上面的Update()

private Transform clicked; //被鼠标点击的物体
void Update()
    {
        if(Input.GetMouseButtonDown(0))
        {//鼠标左键点击,产生一条射线
            //测试Ray,设置射线从主摄像机到鼠标位置
            ray=Camera.main.ScreenPointToRay(Input.mousePosition);
            Physics.Raycast(ray, out RaycastHit hit, 100, LayerMask.GetMask("object"));
            //这里检测object层
            if(hit.collider != null)
            {
                clicked = hit.transform;  //射线检测到的物体之后被鼠标拖拽
            }
        }
        if(Input.GetMouseButton(0))
        {//如果收到鼠标左键持续点击,实现拖拽物体
            if(clicked!= null)
            {
                Vector3 pos=Tools.MouseToWorld(clicked.position);//第三步实现的方法
                clicked.position=new Vector3(pos.x,clicked.position.y,pos.z);
                //物体高度(y)不变
            }
        }
        if(Input.GetMouseButtonUp(0))
        {//如果鼠标左键抬起,释放物体
            clicked= null;
        }
    }

  第三步:如果检测到鼠标左键持续点击,则将鼠标位置转化成三维空间位置赋给物体;

   *注:应用2重点是鼠标位置转换,鼠标的点击位置是一个二维的屏幕位置,需要将之转换为三维空间的位置,这是一个需要经常用到的转换,可以将这个方法放入Tools.cs工具集中。以下就是转换的代码,看似转来转去非常复杂,可以参照文章Unity Camera的ScreenToWorldpoint API的实现了解原理。

    //在Tools工具集中加入一个鼠标坐标转换的工具
    //将鼠标在屏幕上点击的二维坐标转换为空间三维坐标
    public static Vector3 MouseToWorld(Vector3 target)
    {//需要传入一个被点击物体的位置,因为鼠标的坐标原本只有XY,没有Z轴
        //将target的世界坐标转换为屏幕坐标
        Vector3 targetScreen=Camera.main.WorldToScreenPoint(target);
        //将鼠标在屏幕上的XY位置加上target的z位置,得到鼠标的屏幕位置
        Vector3 curseScreenPos=new Vector3(Input.mousePosition.x, Input.mousePosition.y, targetScreen.z);
        //最后将鼠标屏幕位置转为世界位置
        Vector3 curseWorldPos=Camera.main.ScreenToWorldPoint(curseScreenPos);
        return curseWorldPos;
    }

效果如下:

Physics.Linecast和Physics.OverlapSphere

  这两个API都是在线性或球形范围中检测碰撞体,Linecast可以用于射击游戏,而OverlapSphere之前在小游戏坦克对战中使用过。它们的语法如下:

//线性检测
public static bool Linecast(Vector3 start, Vector3 end, out RaycastHit hitInfo)

public static bool Linecast(Vector3 start, Vector3 end, int layerMask)

//球形检测,返回一个数组,列出所有被检测到的碰撞器
public static Collider[] OverlapSphere(Vector3 position, float radius)

public static Collider[] OverlapSphere(Vector3 position, float radius, int layerMask)

应用3:进入范围时触发攻击

  简单做一个类似与以前做过的“坦克对战”效果。新建一个挂在主角Hero上的脚本OverlapSphere.cs

public class OverlapSphere : MonoBehaviour
{
    private Collider[] colliders;
    private GameObject bullet;

    void Update()
    {
        colliders=Physics.OverlapSphere(transform.position, 2, LayerMask.GetMask("Enemy"));
        //设定圆心、半径、检测层
        foreach(var collider in colliders)
        {
            bullet = Resload.Instance.LoadPrefab("Bullet");//加载子弹
            bullet.transform.position = transform.position;
            bullet.transform.LookAt(collider.transform);
        }
    }
}

 效果如下:

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值