第二十八章 Unity射线检测

2023-11-16

本章节我们介绍一下射线。射线就是从一个固定点向一个方向发射出一条直线,在发射过程中需要判断该射线有没有与游戏物体发送碰撞。射线既可以用来检测射击游戏中武器指向目标;又可以判断鼠标是否指向游戏物体。射线的创建方式,一般使用代码来实现。接下来,我们就来创建一个新的“SampleScene3.unity”场景。这里注意的是,射线检测都是以物理系统为基础的,因此只有添加碰撞体组件的游戏物体才能被射线检测到。庆幸的是,在Unity中,创建的Cube或者Sphere,都是自动附带相应的碰撞体组件。

我们创建了三个球体Sphere1,Sphere2,Sphere3,然后我们由Sphere1为起点向X轴负方向(上图左边)发射一条射线。那么这条射线就应该可以检测到Sphere2和Sphere3。

接下来,我们创建一个“RayScript.cs”脚本文件,附加到Sphere1上面,内容如下。

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

public class RayScript : MonoBehaviour
{
    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.A))
        {
            // 射线的起点(Sphere1的位置)
            Vector3 origin = transform.position;
            // 射线的方向(X轴负方向)
            Vector3 direction = Vector3.left;
            // 射线碰撞的目标对象
            RaycastHit hitInfo;
            // 射线的最大长度
            float maxDistance = 100;

            // 创建射线,返回是否检测到碰撞对象
            bool raycast = Physics.Raycast(origin, direction, out hitInfo, maxDistance);

            // 如果发生碰撞,碰撞信息就被存储到 hitInfo 中
            if (raycast)
            {
                // 获取碰撞点坐标
                Vector3 point = hitInfo.point;
                Debug.Log("碰撞点坐标:" + point);

                // 获取碰撞目标的名称
                string name = hitInfo.collider.name;
                Debug.Log("碰撞对象名称:" + name);

                // 获取目标的碰撞体组件
                Collider coll = hitInfo.collider;

                //获取目标的Transgorm组件
                Transform trans = hitInfo.transform;
            }
        }
    }
}

上面的代码非常简单,我们使用四个参数来,通过Physics.Raycast方法创建一条射线,然后使用第三个参数RaycastHit hitInfo就是我们需要的碰撞目标的信息。我们可以通过这个对象获取到射线和目标的碰撞点位置信息,也可以获取目标的游戏对象名称,以及它碰撞体collider组件或者transform变换组件。其实,Physics.Raycast方法还有第五个参数int layerMask,用来指定检测图层,而忽略其他图层。在我们上一章节中,就提到过,碰撞检测可以使用层layer来进行限制。我们可以指定层与层之间的游戏对象发生碰撞,同样这里也适用于射线的碰撞检测。这里我们就不再详细介绍这个参数了。

在游戏开发中,由于射线不可见,所以有时候,我们无法判断射线碰撞的有效性。这个时候,我们可以借助Debug.DrawLine()函数和Debug.DrawRay()来模拟射线。首先介绍DrawLine,

Debug.DrawLine(Vector3 start, Vector3 end, Color color=Color.white, float duration=0.0f, bool depthTest=true);

参数为start 直线的起点,end 直线的终点,color 直线的颜色,duration 直线的持续时间。

depthTest 直线是否被靠近摄像机的对象遮挡。

Debug.DrawRay(Vector3 start, Vector3 dir, Color color=Color.white, float duration=0.0f, bool depthTest=true);

参数为start 射线的起点,dir 射线的方向和长度,color 射线的颜色,duration 射线的持续时间,depthTest 摄像是否被靠近摄像机的对象遮挡。

接下来,我们就使用Debug.DrawRay方法来模拟上面代码案例中的摄像,增加如下代码

// 画一条蓝线来模拟射线
Debug.DrawRay(origin, direction * 100, Color.blue, 100);

接下来,我们重新Play工程,然后按下A键,回到Scene视图(不是Game视图)中查看。

我们可以看到由Sphere1发射出来的一条蓝色的模拟射线了。

由上图我们可知,射线不仅穿过了黄球Sphere2,还穿过了绿球Sphere3了。如何能得到绿色Sphere3呢?这个就需要借助Physics.RaycastAll函数。这个函数与Physics.Raycast函数的使用是相似的,但是返回的结果是不一样的。该函数的返回值是RaycastHit数组。接下来,我们重新修改一下代码,如下所示

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.A))
        {
            // 射线的起点(Sphere1的位置)
            Vector3 origin = transform.position;
            // 射线的方向(X轴负方向)
            Vector3 direction = Vector3.left;
            // 射线碰撞的目标对象
            //RaycastHit hitInfo;
            // 射线的最大长度
            float maxDistance = 100;

            // 创建射线,返回是否检测到碰撞对象
            //bool raycast = Physics.Raycast(origin, direction, out hitInfo, maxDistance);
            RaycastHit[] hitInfos = Physics.RaycastAll(origin, direction, maxDistance);

            // 如果发生碰撞,碰撞信息就被存储到 hitInfo 中
            //if (raycast)
            foreach(RaycastHit hitInfo in hitInfos)
            {
                // 获取碰撞点坐标
                Vector3 point = hitInfo.point;
                Debug.Log("碰撞点坐标:" + point);

                // 获取碰撞目标的名称
                string name = hitInfo.collider.name;
                Debug.Log("碰撞对象名称:" + name);

                // 获取目标的碰撞体组件
                Collider coll = hitInfo.collider;

                //获取目标的Transgorm组件
                Transform trans = hitInfo.transform;
            }

            // 画一条蓝线来模拟射线
            Debug.DrawRay(origin, direction * 100, Color.blue, 100);
        }
    }

我们重新Play工程,控制台输出截图如下

在实际游戏开发中,我们有时候需要检测一定范围内是否发生碰撞。比如说,我们要检测周围100米内是否存在某些游戏对象,如果存在,就向其主动发起攻击。此时,我们使用一条射线就无法完成这样的要求。Unity为我们提供了丰富的不同形状的射线检测。这里,我们可以使用Physics.OverlapSphere创建球体碰撞检测,或者使用Physics.OverlapBox创建立方体检测。他们返回的是Collider[]数组,例如我们使用射线检测附近100米内的所有物体

Collider[] colliders = Physics.OverlapSphere(transform.postion, 100.0f);

foreach(Collider collider in colliders){ …… }

最后,我们在介绍一下摄像的另一种使用方式,就是鼠标点击选中场景中的游戏对象。它的原理非常简单,就是由相机位置向鼠标点击位置发射一条射线,然后进行碰撞检测。接下来,我们就来创建一个“RayClickScript.cs”脚本,将其附加到相机上面。

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

public class RayClickScript : MonoBehaviour
{
    // Update is called once per frame
    void Update()
    {
        // 鼠标左键按下
        if (Input.GetMouseButtonDown(0))
        {
            // 从相机位置发射一条射线经过屏幕上的鼠标点击位置
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

            // 声明一个射线碰撞信息类
            RaycastHit hit;

            // 进行碰撞检测
            bool res = Physics.Raycast(ray, out hit);

            // 如果产生了碰撞
            if(res){
                Debug.Log("碰撞点:" + hit.point);
                Debug.Log("碰撞目标:" + hit.transform.name);
            }
        }
    }
}

然后我们Play工程,使用鼠标点击绿球Sphere3,

接下来,我们做一个有趣事情。我们点击Plane平面上一点,然后让绿球Sphere3移动到那一点。如何来完成这件有趣的事情呢?代码改动如下

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

public class RayClickScript : MonoBehaviour
{
    // 绿球Sphere3
    private GameObject sphere3;

    // 是否移动
    private bool isMove = false;

    // 目标点
    private Vector3 target = Vector3.zero;

    // Start is called before the first frame update
    void Start()
    {
        // 获取绿球Sphere3
        sphere3 = GameObject.Find("Sphere3");
    }

    // Update is called once per frame
    void Update()
    {
        // 鼠标左键按下
        if (Input.GetMouseButtonDown(0))
        {
            // 从相机位置发射一条射线经过屏幕上的鼠标点击位置
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

            // 声明一个射线碰撞信息类
            RaycastHit hit;

            // 进行碰撞检测
            bool res = Physics.Raycast(ray, out hit);

            // 如果产生了碰撞
            if (res && hit.transform.name == "Plane")
            {
                // 目标点(Y轴上保持不变)
                isMove = true;
                target = new Vector3(hit.point.x, sphere3.transform.position.y, hit.point.z);
                //Debug.Log("碰撞点:" + hit.point);
                //Debug.Log("碰撞目标:" + hit.transform.name);
            }
        }

        // 如果发生碰撞就让绿球移动到目标点
        if (isMove)
        {
            // 绿球朝向目标点
            sphere3.transform.LookAt(target);

            // 角色移动到目标点的距离
            float distance = Vector3.Distance(target, sphere3.transform.position);

            // 没有到达目标点就一直移动下去
            if (distance > 0.1f)
            {
                // 旋转后向前移动即可
                sphere3.transform.Translate(transform.forward * 0.2f);
            }
            else
            {
                // 移动结束
                isMove = false;
            }
        }
    }
}

上面的代码,我们就不解释了,直接Play运行查看效果

本课程涉及的内容已经共享到百度网盘:https://pan.baidu.com/s/1e1jClK3MnN66GlxBmqoJWA?pwd=b2id

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

第二十八章 Unity射线检测 的相关文章

  • halfShader 模型切割

    Shader Unlit halfShader Properties Diffuse Diffuse Color 1 1 1 1 MainTex Texture 2D white StartCutoff StartCutoff Range
  • unity粒子特效附上贴图后播放动画

    转自 http jingyan baidu com article f96699bbb1a0d6894f3c1b77 html 参考 http www unitymanual com thread 2993 1 1 html dsign a
  • UnityLuaMvvM Lua 带通知的Mode类

    实现数据更新UI自动刷新的核心代码 欢迎关注https gitee com xiongks UnityMVVM mode function modeType local obj obj modeType modeType obj filds
  • Unity3d Terrain地形制作系列(一)

    游戏简单地形 地形制作 地形制作 第一步在场景里加载一个地形对象 第二步 我们在属性面板里找到绘制地形 然后选择Set Height 绘制高度 应该我们要制作低凹的效果 所有先让他有个高度 不然是不能实现低凹的效果 如图 我们然后选择绘制地
  • Unity WebGL错误集锦

    ips 0 Unity的PlayerSettings的otherSettings或者Publish Settings里面的Enable Exceptions里面选择Full StackTrace 可以在打出的包中的浏览器的webgl打印出错
  • 蒙特卡洛积分、重要性采样、低差异序列

    渲染公式 渲染的目标在于计算周围环境的光线有多少从表面像素点反射到相机视口中 要计算总的反射光 每个入射方向的贡献 必须将他们在半球上相加 为入射光线 与法线 的夹角 为方便计算可以使用法线向量和入射向量 单位化 的乘积表示 对于基于图像的
  • 【Unity&C#&随机数】随机数

    一个简单的随机数获得 0或1 使用了这样的代码 想要获得0或者1 if Input anyKeyDown float i 1 if i 1 i Random Range 0 Rang i i lt 0 5 0 1 Debug Log Cou
  • Unity 安卓打包

    Unity打包的方式有很多种 自动打包和手动打包 今天小弟就鼓捣鼓捣unity手动打包 如果想动态打包的话 可以去看其他大佬的帖帖哈 unity打包先配置环境 下载unity的时候可以顺道把unity的安卓包下载下来 如果忘了也没事 可以从
  • 1.17 从0开始学习Unity游戏开发--场景切换

    前面的所有文章我们都在一个固定的游戏场景内进行开发 在最开始介绍场景这个概念的时候就已经提及 这个场景可以是一张地图 或者是一个对战房间等等 所以显然这个场景可以有多个 并且可以从一个场景切换到另外一个场景 那么在Unity中如何进行场景切
  • Unity 分块延迟渲染01 (TBDR)

    现代移动端图形体系结构的概述 现代SoC通常会同时集成CPU和GPU CPU被用于处理需要低内存延迟的序列 大量分支的数据集 其晶体管用于流控制和数据缓存 GPU为处理大型 未分支的数据集 如3D渲染 晶体管专用于寄存器和算术逻辑单元 而不
  • Unity之获取游戏物体对象或组件的几个方法

    文章目录 前言 通过物体名称获取对象 GameObject Find Transform Find 通过物体标签获取对象 GameObject FindWithTag GameObject FindGameObjectWithTag Gam
  • GooglePlay提审警告(com.google.android.gms:play-services-safetynet:17.0.0)

    1 Goole在今年6月份出的新政策 不在使用safetynet 而使用Play Integrity API 2 项目本身没有使用过safetynet 3 使用了firebase 查阅资料 解决方案如下 implementation pla
  • VLC for unity 插件如何使用

    VLC for unity 插件如何使用 先去下载一个VLC播放器 安装完成后 然后导入插件链接https download csdn net my 这个插件我的另一个上传资源里有 或者到商店去下载 这个插件链接下载完是一个txt文档 里面
  • Unity保存图片到相册

    Unity保存图片到Android相册 Java 纯文本查看 复制代码 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
  • 【Unity步步升】监控与检测物体的各种方案,如:射线、碰撞、挂载等...

    在制作AR模型数值控制方案的时候遇到了检测的问题 学习过程受益匪浅 故今天为大家整理带来一篇监控与检测物体的参考方案集合 目录 一 射线检测 二 物体存在检测 三 碰撞检测 一 射线检测 单射线检测 首先完成搭建场景如下图1 1 我这里用到
  • Unity万向节死锁解决方案(2023/12/4)

    1 万向节死锁无法解决 这是因为它的特性就是如此 就像玻璃杯就是玻璃 这不可否认 别钻牛角尖昂 2 大多数情况下欧拉角足够用 例如 CF 摄像机不可能绕z轴旋转 x轴旋转也不会超过九十度 因为那样人物的腰子会被扭断 塔防游戏 保卫萝卜 吃鸡
  • Unity学习笔记

    一 旋转欧拉角 四元数 Vector3 rotate new Vector3 0 30 0 Quaternion quaternion Quaternion identity quaternion Quaternion Euler rota
  • Unity中URP下的指数雾

    文章目录 前言 一 指数雾 雾效因子 1 FOG EXP 2 FOG EXP2 二 MixFog 1 ComputeFogIntensity 雾效强度计算 2 lerp fogColor fragColor fogIntensity 雾效颜
  • 游戏开发常见操作梳理系列之——玩家信息的显示系统

    在游戏中 有不少游戏在左上角会出现玩家的头像和等级以及血量 这就是玩家的信息显示系统 那么这些是如何制作的呢 接下来我将讲讲代码的操作 其它操作我会在其它笔记中一一说明 敬请期待 信息的显示相当简单就是控制一些UI 然后在其它系统里面填写相
  • 游戏开发常见操作梳理之小地图的制作

    游戏中一般存在小地图系统 实际上就是设置一个新的摄像机放置在玩家的正上方 然后在小地图上显示新摄像机看见的东西就可以了 在小地图上一般存在放大地图和缩小地图的按钮可以方便放大和缩小地图 这些操作是如何实现的呢 接下来直接上核心代码 usin

随机推荐

  • CVPR 2021 Sequential Graph Convolutional Network for Active Learning

    深度学习在计算机视觉方面展现出非常大的进步 其代价是大规模的标注数据集 数据标注是耗时的 需要人工和雇佣成本 在许多领域 数据标注更具挑战性 如医学成像领域 此外 在优化深层神经网络架构时 数据的代表性存在差距 为了克服这些问题 主动学习已
  • HTTP协议之Libcurl

    目录 转载 https www cnblogs com xietianjiao p 13260021 html 一 libcurl简介 二 libcurl的使用 三 libcurl等第三方库的通用编译方法 四 调用libcurl编程访问百度
  • Elasticsearch(八)搜索优化

    Elasticsearch 6 4 2 1 理解字段分析过程 一个常被问到的问题是 为什么指定的文档没有被搜索到 很多情况下 这都归因于映射的定义和分析例程的配置存在问题 针对分析过程的调试 Elasticsearch提供了专用的REST
  • h5py存取简例

    当数据太大 好像是 gt 2G scipy io savemat 会报错 考虑换用 h5py 这种格式 matlab 也可以读 见 4 Code import numpy as np import h5py a np arange 12 r
  • SiamMask 测试程序分析

    之前分析了 DaSiamRPN 的测试代码 侧重于执行细节 到了 SiamMask 似乎主题应该有所升华 故事的明线为跟踪器构成 暗线为训练流图 相比于 DaSiamRPN SiamMask 不仅网络结构是现代化的 系统设计也更具匠心 这便
  • MATLAB——参数根轨迹的绘制

  • C# 接口(Interface)

    简介 接口定义了所有类继承接口时应遵循的语法合同 接口定义了属性 方法和事件 这些都是接口的成员 接口只包含了成员的声明 成员的定义是派生类的责任 接口提供了派生类应遵循的标准结构 接口使得实现接口的类或结构在形式上保持一致 抽象类在某种程
  • 双fifo流水线实现3x1024数组数据按列相加

    Vivado版本 2019 2 MATLAB Modelsim版本 Modelsim SE 64 10 7 实验内容 双fifo流水线实现3x1024数组数据按列相加 FIFO First Input First Output 既先入先出
  • 小程序 云函数中file转base64

    mp4文件转base64 云函数中下载文件 const res await cloud downloadFile fileID fileID const base64 data video mp4 base64 res fileConten
  • 计算机编程语言:解释型语言与编译型语言的理解

    一 计算机编程语言 主要分为3类 高级语言 抽象层次更高的便于记忆和表示的英文代码 汇编语言 抽象层次较高的对应机器硬件的cpu指令集 英文缩的助记 符号代码 机器语言 抽像层次最低的由0 1序列所表示的机器码 计算机底层只能识别0 1 所
  • TIMIT数据集无法打开?sph格式转换为wav

    打开TIMIT数据集发现提示无法打开文件 上网搜索发现文件虽然后缀是WAV 但是其实是sph格式 是无法打开的 需要转换为wav 找到一种python方法转换格式 但是不知道为什么sphfile库下载安装了就是无法引用 然后又找到了一个ma
  • Linux 安装Zookeeper

    Linux 安装Zookeeper 下载 wget https mirrors tuna tsinghua edu cn apache zookeeper zookeeper 3 4 14 解压 tar zxvf zookeeper 3 4
  • qt学习笔记2:信号和槽

    信号和槽 实现点击按钮关闭窗口 按钮 gt 点击 gt 窗口 gt 关闭 connect 信号的发送者 发送的具体信号 信号的接收者 信号的处理 信号的处理就是槽 一个是信号的发送方 一个是信号的接收方 信号槽有一个优点 松散耦合 即发送方
  • Vue 复杂json数据在el-table表格中展示(el-table分割数据)

    文章目录 前言 问题背景 实现复杂json数据在el table表格展示 el table column分割线 el table column高度 前言 在做复杂的动态表单 实现业务动态变动 比如有一条需要动态添加的el form item
  • Day29_10 JavaWeb之编码处理、Jsp及Cookie的使用(记住密码)

    目录 一 编码处理 编码处理的意义 请求编码及响应编码 二 Jsp Jsp的概述 html 转换为jsp 三 Cookie Cookie的概述 Cookie细节 四 记住密码的实现 了解什么是会话跟踪技术 记住密码功能实现的思路 一 编码处
  • Python中安装pandas出现问题总结

    1 安装pandas总报超时 这个方法一般都能解决问题 解决方法 pip install 包名 i http pypi douban com simple trusted host pypi douban com 这个是因为你下载的包不对
  • app 自动化测试 - 多设备并发 -appium+pytest+ 多线程

    1 appium python 实现单设备的 app 自动化测试 启动 appium server 占用端口 4723 电脑与一个设备连接 通过 adb devices 获取已连接的设备 在 python 代码当中 编写启动参数 通过 py
  • tmux内外vim主题theme不一致

    每次在tmux里边用vim都觉得好丑 明明外边设置theme了 但是到里边就识别不了 在 tmux conf里添加set g default terminal screen 256color 依然不行 解决方案 使用tmux 2 打开tmu
  • cdh下spark2-yarn运行sparkstreaming获取kafka数据使用spark-streaming-kafka-0-10_2.11报错解决

    报错问题 20 07 15 17 20 51 INFO utils AppInfoParser Kafka version 0 9 0 kafka 2 0 0 20 07 15 17 20 51 INFO utils AppInfoPars
  • 第二十八章 Unity射线检测

    本章节我们介绍一下射线 射线就是从一个固定点向一个方向发射出一条直线 在发射过程中需要判断该射线有没有与游戏物体发送碰撞 射线既可以用来检测射击游戏中武器指向目标 又可以判断鼠标是否指向游戏物体 射线的创建方式 一般使用代码来实现 接下来