24.射线检测

24.核心系统-物理系统-射线检测


24.1 知识点

什么是射线检测

  • 物理系统中
  • 目前我们学习的物体相交判断
  • 碰撞检测 - 必备条件 - 1刚体 2碰撞器
  • 范围检测 - 必备条件 - 碰撞器

如果想要做这样的碰撞检测呢?

  • 鼠标选择场景上一物体
  • FPS射击游戏(无弹道-不产生实际的子弹对象进行移动)
  • 等等 需要判断一条线和物体的碰撞情况

射线检测 就是来解决这些问题的

  • 它可以在指定点发射一个指定方向的射线
  • 判断该射线与哪些碰撞器相交,得到对应对象

射线对象

Ray射线类

假设有一条起点为坐标(1,0,0) 方向为世界坐标Z轴正方向的射线

Ray的无参构造函数
  • 一般不会用无参构造初始化射线,因为后面还需要重新设置,很麻烦
Ray ray1 = new Ray();
ray1.origin = Vector3.right;
ray1.direction = Vector3.forward;
Ray的有参构造函数
  • 参数一:起点
  • 参数二:方向
Ray ray2 = new Ray(Vector3.right, Vector3.forward);
Ray.origin变量 射线的起点
//Ray中的origin变量 起点
//射线的原点。
print(ray2.origin);//起点
Ray.direction变量 射线的方向
//Ray中的direction变量 方向
//射线的方向。
print(ray2.direction);//方向

Camera.ScreenPointToRay方法 摄像机发射出的射线

  • 返回从摄像机通过屏幕点的光线
  • 得到一条从屏幕位置作为起点,摄像机视口方向为方向的射线
Ray ray3 = Camera.main.ScreenPointToRay(Input.mousePosition);

注意:射线要结合物理系统

  • 单独的射线对于我们来说没有实际的意义
  • 我们需要用它结合物理系统进行射线碰撞判断

碰撞检测函数

Physics类中提供了很多进行射线检测的静态函数

  • 他们有很多种重载类型,我们只需要掌握核心的几个函数,其它函数自然就明白什么意思了
  • 射线检测也是瞬时的,执行代码时进行一次射线检测

准备一条射线

Ray ray4 = new Ray(Vector3.zero, Vector3.forward);

Physics.Raycast方法 发射射线

向场景中的所有碰撞体投射一条射线,该射线起点为 / origin /,朝向 / direction /,长度为 / maxDistance /。

//Physics.Raycast方法重载 最原始的射线检测 如果碰撞到对象 返回true
//参数一:射线
//参数二: 检测的最大距离 超出这个距离不检测
//参数三:检测指定层级(不填检测所有层)
//参数四:是否忽略触发器 UseGlobal-使用全局设置 不填默认使用UseGlobal 全局设置在ProjectSettings中的Physics里的 Queries Hit Triggers 可以查看并设置
//返回值:bool 当碰撞到对象时 返回 true 没有 返回false
//Physics.Raycast方法不传入RaycastHit对象的话不能得到碰到的对象是谁
if (Physics.Raycast(ray4, 1000, 1 << LayerMask.NameToLayer("Monster"), QueryTriggerInteraction.UseGlobal))
{
    print("碰撞到了对象");
}

//还有一种重载 不用传入 射线 直接传入起点 和 方向 也可以用于判断
//就是把 第一个参数射线 变成了 射线的 两个点 一个起点 一个方向
//Physics.Raycast方法不传入RaycastHit对象的话不能得到碰到的对象是谁
if (Physics.Raycast(Vector3.zero, Vector3.forward, 1000, 1 << LayerMask.NameToLayer("Monster"), QueryTriggerInteraction.UseGlobal))
{
    print("碰撞到了对象2");
}

//Physics.Raycast方法重载 获取相交的单个物体信息 如果碰撞到对象 返回true
//物体信息类 RaycastHit
RaycastHit raycastHitInfo;
//参数一:射线
//参数二:RaycastHit是结构体 是值类型 Unity会通过out 关键字 在函数内部处理后 得到碰撞数据后返回到该参数中
//参数三:距离
//参数四:检测指定层级(不填检测所有层)
//参数五:是否忽略触发器 UseGlobal-使用全局设置 不填默认使用UseGlobal 全局设置在ProjectSettings中的Physics里的 Queries Hit Triggers 可以查看并设置
//Physics.Raycast方法传入RaycastHit对象的话可以得到碰到的对象是谁
if (Physics.Raycast(ray4, out raycastHitInfo, 1000, 1 << LayerMask.NameToLayer("Monster"), QueryTriggerInteraction.UseGlobal))
{
    print("碰撞到了物体 得到了信息");

    //RaycastHit.collider变量 碰撞器信息
    //命中的 Collider。
    print("碰撞到物体的名字" + raycastHitInfo.collider.gameObject.name);

    //RaycastHit.point变量 碰撞到的点
    //世界空间中射线命中碰撞体的撞击点。
    //可以用于射击游戏创建特效 比如被子弹打中飙血,墙壁被打贴图
    print(raycastHitInfo.point);

    //RaycastHit.normal变量 法线信息向量
    //射线命中的表面的法线。
    //可以用于射击游戏特效计算相关 比如被子弹打中后反射的角度 贴图的角度
    print(raycastHitInfo.normal);

    //RaycastHit.transform变量 得到碰撞到对象的位置
    //命中的刚体或碰撞体的 Transform。
    print(raycastHitInfo.transform.position);

    //RaycastHit.distance变量 得到碰撞到对象 离自己的距离
    //从射线原点到撞击点的距离。
    //可能通过距离 模拟子弹受重力影响下落的高度
    print(raycastHitInfo.distance);

    //RaycastHit 该类 对于我们的意义
    //它不仅可以得到我们碰撞到的对象信息
    //还可以得到一些 碰撞的点 距离 法线等等的信息
}

//还有一种重载 不用传入 射线 直接传入起点 和 方向 也可以用于判断
//就是把 第一个参数射线 变成了 射线的 两个点 一个起点 一个方向
//Physics.Raycast方法传入RaycastHit对象的话可以得到碰到的对象是谁
if (Physics.Raycast(Vector3.zero, Vector3.forward, out raycastHitInfo, 1000, 1 << LayerMask.NameToLayer("Monster"), QueryTriggerInteraction.UseGlobal))
{

}

Physics.RaycastAll方法 发射射线 获取相交的多个物体

//Physics.RaycastAll方法 发射射线 获取相交的多个物体 可以得到碰撞到的多个对象 如果没有 就是容量为0的数组
//向场景中投射射线并返回所有命中对象。注意,这些结果的顺序未定义。
//参数一:射线
//参数二:距离
//参数三:检测指定层级(不填检测所有层)
//参数四:是否忽略触发器 UseGlobal-使用全局设置 不填默认使用UseGlobal 全局设置在ProjectSettings中的Physics里的 Queries Hit Triggers 可以查看并设置
//Physics.RaycastAll方法传入RaycastHit数组对象可以得到多个碰到的对象
RaycastHit[] raycastHitInfos = Physics.RaycastAll(ray4, 1000, 1 << LayerMask.NameToLayer("Monster"), QueryTriggerInteraction.UseGlobal);
for (int i = 0; i < raycastHitInfos.Length; i++)
{
    print("碰到的所有物体 名字分别是" + raycastHitInfos[i].collider.gameObject.name);
}
//还有一种重载 不用传入 射线 直接传入起点 和 方向 也可以用于判断
//之前的参数一射线 通过两个点传入
raycastHitInfos = Physics.RaycastAll(Vector3.zero, Vector3.forward, 1000, 1 << LayerMask.NameToLayer("Monster"), QueryTriggerInteraction.UseGlobal);

Physics.RaycastNonAlloc方法 发射射线获取相交的多个物体

//Physics.RaycastNonAlloc方法 发射射线 要传入RaycastHit数组 通过out得到数据赋值到数组中 返回的碰撞的数量 
//向场景中投射射线,并将命中对象存储到缓冲区中。
if (Physics.RaycastNonAlloc(ray4, raycastHitInfos, 1000, 1 << LayerMask.NameToLayer("Monster"), QueryTriggerInteraction.UseGlobal) > 0)
{

}

射线检测使用时注意的问题

  • 距离、层级两个参数都是int类型
  • 当我们传入参数时,一定要明确传入的参数代表的是距离还是层级

举例:

  • 这样写是错误的,因为第二个参数代表的是距离,不是层级
if (Physics.Raycast(ray4, 1 << LayerMask.NameToLayer("Monster")))
{
    // 错误的代码示例
}

24.2 知识点代码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Lesson24_核心系统_物理系统之射线检测 : MonoBehaviour
{
    void Start()
    {
        #region 知识点一 什么是射线检测
        //物理系统中 
        //目前我们学习的物体相交判断
        //1.碰撞检测——必备条件 1刚体2碰撞器
        //2.范围检测——必备条件 碰撞器

        //如果想要做这样的碰撞检测呢?
        //1.鼠标选择场景上一物体
        //2.FPS射击游戏(无弹道-不产生实际的子弹对象进行移动)
        //等等 需要判断一条线和物体的碰撞情况

        //射线检测 就是来解决这些问题的
        //它可以在指定点发射一个指定方向的射线
        //判断该射线与哪些碰撞器相交,得到对应对象
        #endregion

        #region 知识点二 射线对象

        //3D世界中的射线类 Ray

        //假设有一条起点为坐标(1,0,0) 方向为世界坐标Z轴正方向的射线

        //Ray的无参构造函数
        //一般不会用无参构造初始化射线 不然后面还要重新设置 很麻烦
        Ray ray1 = new Ray();
        ray1.origin = Vector3.right;
        ray1.direction = Vector3.forward;

        //Ray的有参构造函数
        //注意:理解参数含义
        //参数一:起点 
        //参数二:方向
        //(一定记住 不是两点决定射线方向,第二个参数 直接就代表方向向量)
        //目前只是声明了一个射线对象 对于我们来说 没有任何的用处
        Ray ray2 = new Ray(Vector3.right, Vector3.forward);

        //Ray中的origin变量 起点
        //射线的原点。
        print(ray2.origin);//起点

        //Ray中的direction变量 方向
        //射线的方向。
        print(ray2.direction);//方向

        //Camera类中的ScreenPointToRay 摄像机发射出的射线
        //返回从摄像机通过屏幕点的光线。
        // 得到一条从屏幕位置作为起点
        // 摄像机视口方向为 方向的射线
        Ray ray3 = Camera.main.ScreenPointToRay(Input.mousePosition);

        //注意:
        //单独的射线对于我们来说没有实际的意义
        //我们需要用它结合物理系统进行射线碰撞判断

        #endregion

        #region 知识点三 碰撞检测函数

        //Physics类中提供了很多进行射线检测的静态函数
        //他们有很多种重载类型 我们只需要掌握核心的几个函数 其它函数自然就明白什么意思了
        //注意:射线检测也是瞬时的 执行代码时进行一次射线检测

        // 准备一条射线
        Ray ray4 = new Ray(Vector3.zero, Vector3.forward);


        //Physics类中的Raycast方法 发射射线
        //向场景中的所有碰撞体投射一条射线,该射线起点为 / origin /,朝向 / direction /,长度为 / maxDistance /。

        //Physics类中的Raycast方法重载 最原始的射线检测 如果碰撞到对象 返回true
        //参数一:射线
        //参数二: 检测的最大距离 超出这个距离不检测
        //参数三:检测指定层级(不填检测所有层)
        //参数四:是否忽略触发器 UseGlobal-使用全局设置 不填默认使用UseGlobal 全局设置在ProjectSettings中的Physics里的 Queries Hit Triggers 可以查看并设置
        //返回值:bool 当碰撞到对象时 返回 true 没有 返回false
        //Physics类中的Raycast方法不传入RaycastHit对象的话不能得到碰到的对象是谁
        if (Physics.Raycast(ray4, 1000, 1 << LayerMask.NameToLayer("Monster"), QueryTriggerInteraction.UseGlobal))
        {
            print("碰撞到了对象");
        }
        //还有一种重载 不用传入 射线 直接传入起点 和 方向 也可以用于判断
        //就是把 第一个参数射线 变成了 射线的 两个点 一个起点 一个方向
        //Physics类中的Raycast方法不传入RaycastHit对象的话不能得到碰到的对象是谁
        if (Physics.Raycast(Vector3.zero, Vector3.forward, 1000, 1 << LayerMask.NameToLayer("Monster"), QueryTriggerInteraction.UseGlobal))
        {
            print("碰撞到了对象2");
        }

        //Physics类中的Raycast方法重载 获取相交的单个物体信息 如果碰撞到对象 返回true
        //物体信息类 RaycastHit
        RaycastHit raycastHitInfo;
        //参数一:射线
        //参数二:RaycastHit是结构体 是值类型 Unity会通过out 关键字 在函数内部处理后 得到碰撞数据后返回到该参数中
        //参数三:距离
        //参数四:检测指定层级(不填检测所有层)
        //参数五:是否忽略触发器 UseGlobal-使用全局设置 不填默认使用UseGlobal 全局设置在ProjectSettings中的Physics里的 Queries Hit Triggers 可以查看并设置
        //Physics类中的Raycast方法传入RaycastHit对象的话可以得到碰到的对象是谁
        if (Physics.Raycast(ray4, out raycastHitInfo, 1000, 1 << LayerMask.NameToLayer("Monster"), QueryTriggerInteraction.UseGlobal))
        {
            print("碰撞到了物体 得到了信息");

            //RaycastHit类中的collider变量 碰撞器信息
            //命中的 Collider。
            print("碰撞到物体的名字" + raycastHitInfo.collider.gameObject.name);

            //RaycastHit类中的point变量 碰撞到的点
            //世界空间中射线命中碰撞体的撞击点。
            //可以用于射击游戏创建特效 比如被子弹打中飙血,墙壁被打贴图
            print(raycastHitInfo.point);

            //RaycastHit类中的normal变量 法线信息向量
            //射线命中的表面的法线。
            //可以用于射击游戏特效计算相关 比如被子弹打中后反射的角度 贴图的角度
            print(raycastHitInfo.normal);

            //RaycastHit类中的transform变量 得到碰撞到对象的位置
            //命中的刚体或碰撞体的 Transform。
            print(raycastHitInfo.transform.position);

            //RaycastHit类中的distance变量 得到碰撞到对象 离自己的距离
            //从射线原点到撞击点的距离。
            //可能通过距离 模拟子弹受重力影响下落的高度
            print(raycastHitInfo.distance);

            //RaycastHit 该类 对于我们的意义
            //它不仅可以得到我们碰撞到的对象信息
            //还可以得到一些 碰撞的点 距离 法线等等的信息
        }
        //还有一种重载 不用传入 射线 直接传入起点 和 方向 也可以用于判断
        //就是把 第一个参数射线 变成了 射线的 两个点 一个起点 一个方向
        //Physics类中的Raycast方法传入RaycastHit对象的话可以得到碰到的对象是谁
        if (Physics.Raycast(Vector3.zero, Vector3.forward, out raycastHitInfo, 1000, 1 << LayerMask.NameToLayer("Monster"), QueryTriggerInteraction.UseGlobal))
        {

        }


        //Physics类中的RaycastAll方法 发射射线 获取相交的多个物体 可以得到碰撞到的多个对象 如果没有 就是容量为0的数组
        //向场景中投射射线并返回所有命中对象。注意,这些结果的顺序未定义。
        //参数一:射线
        //参数二:距离
        //参数三:检测指定层级(不填检测所有层)
        //参数四:是否忽略触发器 UseGlobal-使用全局设置 不填默认使用UseGlobal 全局设置在ProjectSettings中的Physics里的 Queries Hit Triggers 可以查看并设置
        //Physics类中的RaycastAll方法传入RaycastHit数组对象可以得到多个碰到的对象
        RaycastHit[] raycastHitInfos = Physics.RaycastAll(ray4, 1000, 1 << LayerMask.NameToLayer("Monster"), QueryTriggerInteraction.UseGlobal);
        for (int i = 0; i < raycastHitInfos.Length; i++)
        {
            print("碰到的所有物体 名字分别是" + raycastHitInfos[i].collider.gameObject.name);
        }
        //还有一种重载 不用传入 射线 直接传入起点 和 方向 也可以用于判断
        //之前的参数一射线 通过两个点传入
        raycastHitInfos = Physics.RaycastAll(Vector3.zero, Vector3.forward, 1000, 1 << LayerMask.NameToLayer("Monster"), QueryTriggerInteraction.UseGlobal);


        //Physics类中的RaycastNonAlloc方法 发射射线 要传入RaycastHit数组 通过out得到数据赋值到数组中 返回的碰撞的数量 
        //向场景中投射射线,并将命中对象存储到缓冲区中。
        if (Physics.RaycastNonAlloc(ray4, raycastHitInfos, 1000, 1 << LayerMask.NameToLayer("Monster"), QueryTriggerInteraction.UseGlobal) > 0)
        {

        }

        #endregion

        #region 知识点四 使用时注意的问题

        //注意:
        //距离、层级两个参数 都是int类型
        //当我们传入参数时 一定要明确传入的参数代表的是距离还是层级

        //举例
        //这样写是错误的 因为第二个参数 代表的是距离 不是层级
        if (Physics.Raycast(ray4, 1 << LayerMask.NameToLayer("Monster")))
        {

        }

        #endregion
    }
}

24.3 练习题

请用资料区给的资源,实现鼠标点击场景上一面墙,在点击的位置创建子弹特效和弹孔

void Update()
{
    // 将鼠标在屏幕上的位置通过主相机转换为世界坐标系中的一条视线射线并赋值给 ray1。
    Ray ray1 = Camera.main.ScreenPointToRay(Input.mousePosition);

    // 通过 Debug.DrawRay 方法可将检测到的射线绘制出来以便调试查看(仅在编辑模式下生效)。
    Debug.DrawRay(ray1.origin, ray1.direction);

    // 当鼠标左键被按下时进入条件语句块,通过 Physics.Raycast 方法检测碰撞对象,并在其前方创建打击特效和弹孔。
    if (Input.GetMouseButtonDown(0))
    {
        if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out info, 1000, 1 << LayerMask.NameToLayer("Monster")))
        {
            // 通过 Resources.Load 方法加载名为 "HitEff" 的预制件并实例化一个游戏对象,赋值给 obj。
            GameObject obj = Instantiate(Resources.Load<GameObject>("Effect/HitEff"));

            // 设定打击特效在发生碰撞的物体前方偏移 0.2 米处,绕着所接触的表面产生向外倾斜的弧形运动,并在场景中呈现出来。
            obj.transform.position = info.point + info.normal * 0.2f;

            // 根据所接触的表面法线调整特效预制件的朝向角度,以适应目标物体产生视觉效果。
            obj.transform.rotation = Quaternion.LookRotation(info.normal);

            //销毁特效 Game Object 对象,在指定时间 delay 后进行操作删除。
            Destroy(obj, 0.8f);

            // 创建另一种打击类型的特效 DDD 并将其向量赋值给 obj。
            obj = Instantiate(Resources.Load<GameObject>("Effect/DDD"));

            // 设定打击特效在发生碰撞的物体前方偏移 0.2 米处,绕着所接触的表面产生向外倾斜的弧形运动,并在场景中呈现出来。
            obj.transform.position = info.point + info.normal * 0.2f;

            // 根据所接触的表面法线调整特效预制件的朝向角度,以适应目标物体产生视觉效果。
            obj.transform.rotation = Quaternion.LookRotation(info.normal);
        }
    }
}

场景上有一个平面,有一个立方体,当鼠标点击选中立方体时,长按鼠标左键 可以拖动立方体 在平面上移动,点击鼠标右键取消选中

// 声明一个公共浮点型变量 offsetY,用于设定物体拖曳时的高度偏移量。
public float offsetY;

// 声明一个私有 Transform 类型变量 nowSelObj,用于记录当前选中的对象的 Transform 组件。
private Transform nowSelObj;

// 创建一个 RaycastHit 类型的 info 变量。
RaycastHit info;

void Update()
{
    //场景上有一个平面,有一个立方体,当鼠标点击选中立方体时,长按鼠标左键 可以拖动立方体 在平面上移动,点击鼠标右键取消选中

    // 检测鼠标左键是否按下并检测到对象(Layer 为 Player),并将所检测到的 Game Object 的 Transform 组件赋值给 nowSelObj。
    if (Input.GetMouseButtonDown(0))
    {
        if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out info, 1000, 1 << LayerMask.NameToLayer("Player")))
        {
            //记录选中物体的Transform组件和位置信息
            nowSelObj = info.transform;
            print("选中" + nowSelObj.name);
        }
    }

    // 判断当前是否有选中的物体且左键长按处于开启状态下,将选中的物体沿着平面上的坐标轴向移动指定高度。
    if (Input.GetMouseButton(0) && nowSelObj != null)
    {
        //注意:地板要改成Floor层级 进行射线检测
        if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out info, 1000, 1 << LayerMask.NameToLayer("Floor")))
        {
            //使用偏移量 offsetY 避免立方体与平面粘合
            nowSelObj.position = info.point + Vector3.up * offsetY;
        }
    }

    // 判断右键是否被按下,若是则清除 nowSelObj 记录。
    if (Input.GetMouseButtonDown(1))
    {
        print("取消选中" + nowSelObj.name);
        //取消记录当前已经选中的Transform组件
        nowSelObj = null;
    }
}

24.4 练习题代码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Lesson24_练习题 : MonoBehaviour
{
    // 声明一个公共浮点型变量 offsetY,用于设定物体拖曳时的高度偏移量。
    public float offsetY;

    // 声明一个私有 Transform 类型变量 nowSelObj,用于记录当前选中的对象的 Transform 组件。
    private Transform nowSelObj;

    // 创建一个 RaycastHit 类型的 info 变量。
    RaycastHit info;

    void Update()
    {
        #region 练习题一
        //请用资料区给的资源,实现鼠标点击场景上一面墙,在点击的位置创建子弹特效和弹孔

        // 将鼠标在屏幕上的位置通过主相机转换为世界坐标系中的一条视线射线并赋值给 ray1。
        Ray ray1 = Camera.main.ScreenPointToRay(Input.mousePosition);

        // 通过 Debug.DrawRay 方法可将检测到的射线绘制出来以便调试查看(仅在编辑模式下生效)。
        Debug.DrawRay(ray1.origin, ray1.direction);

        // 当鼠标左键被按下时进入条件语句块,通过 Physics.Raycast 方法检测碰撞对象,并在其前方创建打击特效和弹孔。
        if (Input.GetMouseButtonDown(0))
        {
            if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out info, 1000, 1 << LayerMask.NameToLayer("Monster")))
            {
                // 通过 Resources.Load 方法加载名为 "HitEff" 的预制件并实例化一个游戏对象,赋值给 obj。
                GameObject obj = Instantiate(Resources.Load<GameObject>("Effect/HitEff"));

                // 设定打击特效在发生碰撞的物体前方偏移 0.2 米处,绕着所接触的表面产生向外倾斜的弧形运动,并在场景中呈现出来。
                obj.transform.position = info.point + info.normal * 0.2f;

                // 根据所接触的表面法线调整特效预制件的朝向角度,以适应目标物体产生视觉效果。
                obj.transform.rotation = Quaternion.LookRotation(info.normal);

                //销毁特效 Game Object 对象,在指定时间 delay 后进行操作删除。
                Destroy(obj, 0.8f);

                // 创建另一种打击类型的特效 DDD 并将其向量赋值给 obj。
                obj = Instantiate(Resources.Load<GameObject>("Effect/DDD"));

                // 设定打击特效在发生碰撞的物体前方偏移 0.2 米处,绕着所接触的表面产生向外倾斜的弧形运动,并在场景中呈现出来。
                obj.transform.position = info.point + info.normal * 0.2f;

                // 根据所接触的表面法线调整特效预制件的朝向角度,以适应目标物体产生视觉效果。
                obj.transform.rotation = Quaternion.LookRotation(info.normal);
            }
        }

        #endregion

        #region 练习题二
        //场景上有一个平面,有一个立方体,当鼠标点击选中立方体时,长按鼠标左键 可以拖动立方体 在平面上移动,点击鼠标右键取消选中

        // 检测鼠标左键是否按下并检测到对象(Layer 为 Player),并将所检测到的 Game Object 的 Transform 组件赋值给 nowSelObj。
        if (Input.GetMouseButtonDown(0))
        {
            if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out info, 1000, 1 << LayerMask.NameToLayer("Player")))
            {
                //记录选中物体的Transform组件和位置信息
                nowSelObj = info.transform;
                print("选中" + nowSelObj.name);
            }
        }

        // 判断当前是否有选中的物体且左键长按处于开启状态下,将选中的物体沿着平面上的坐标轴向移动指定高度。
        if (Input.GetMouseButton(0) && nowSelObj != null)
        {
            //注意:地板要改成Floor层级 进行射线检测
            if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out info, 1000, 1 << LayerMask.NameToLayer("Floor")))
            {
                //使用偏移量 offsetY 避免立方体与平面粘合
                nowSelObj.position = info.point + Vector3.up * offsetY;
            }
        }

        // 判断右键是否被按下,若是则清除 nowSelObj 记录。
        if (Input.GetMouseButtonDown(1))
        {
            print("取消选中" + nowSelObj.name);
            //取消记录当前已经选中的Transform组件
            nowSelObj = null;
        }
        #endregion
    }
}


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏