Unity基础5——物理检测

news2024/11/26 23:37:38

一、层级 Layer

​ Unity 中设置了共 32 层 Layer,如图,可以点击 Add Layer 添加自定义的 Layer

​ 通过名字得到层级编号 LayerMask.NameToLayer(string layer)
​ 我们需要通过编号左移构建二进制数,这样每一个编号的层级都是对应位为 1 的 2 进制数
​ 我们通过位运算可以选择想要检测层级,使用一个 int 就可以表示所有想要检测的层级信息

​ 层级编号是 0 ~ 31,刚好 32 位,是一个 int 数
​ 每一个编号代表的都是二进制的一位,例如
0 — — 1 < < 0 — — 0000 0000 0000 0000 0000 0000 0000 0001 = 1 1 — — 1 < < 1 — — 0000 0000 0000 0000 0000 0000 0000 0010 = 2 2 — — 1 < < 2 — — 0000 0000 0000 0000 0000 0000 0000 0100 = 4 3 — — 1 < < 3 — — 0000 0000 0000 0000 0000 0000 0000 1000 = 8 4 — — 1 < < 4 — — 0000 0000 0000 0000 0000 0000 0001 0000 = 16 5 — — 1 < < 5 — — 0000 0000 0000 0000 0000 0000 0010 0000 = 32

二、范围检测

​ 游戏中瞬时的攻击范围判断一般会使用范围检测
​ 举例:

  • 玩家在前方 5m 处释放一个地刺魔法,在此处范围内的对象将受到地刺伤害
  • 玩家攻击,在前方 1 米圆形范围内对象都受到伤害

​ 等等
​ 类似这种并没有实体物体,只想要检测在指定某一范围是否让敌方受到伤害时,便可以使用范围判断
​ 简而言之,在指定位置进行范围判断,我们可以得到处于指定范围内的对象,目的是对对象进行处理
​ 比如受伤、减血等等

​ 必备条件:想要被范围检测到的对象,必须具备碰撞器 Collider
​ 注意点:

  • 范围检测相关 API,只有当执行该句代码时进行一次范围检测,它是瞬时的
  • 范围检测相关 API,并不会真正产生一个碰撞器,只是碰撞判断计算而已

(一)盒状范围检测

// 1.盒状范围检测
// 参数一:立方体中心点
// 参数二:立方体三边大小
// 参数三:立方体角度
// 参数四:检测指定层级(不填检测所有层)
// 参数五:是否忽略触发器 不填使用UseGlobal
//        UseGlobal-使用全局设置 
//        Collide-检测触发器 
//        Ignore-忽略触发器 
// 返回值:在该范围内的触发器(得到了对象触发器就可以得到对象的所有信息)
print(LayerMask.NameToLayer("UI"));
Collider[] colliders = Physics.OverlapBox(Vector3.zero, Vector3.one, Quaternion.AngleAxis(45, Vector3.up),
                                          (1 << LayerMask.NameToLayer("UI")) | (1 << LayerMask.NameToLayer("Default")),
                                          QueryTriggerInteraction.UseGlobal);

// 另一个API 将碰撞器存入给定的数组中
// 返回值:碰撞到的碰撞器数量
// 参数:传入一个数组进行存储
// Physics.OverlapBoxNonAlloc()
if (Physics.OverlapBoxNonAlloc(Vector3.zero, Vector3.one, colliders) != 0) { }

​ 其中,参数五的 UseGlobal 在 Eidt / Project Settings / Physics 中设置

(二)球形范围检测

// 2.球形范围检测
// 参数一:中心点
// 参数二:球半径
// 参数三:检测指定层级(不填检测所有层)
// 参数四:是否忽略触发器 不填使用UseGlobal
//        UseGlobal-使用全局设置 
//        Collide-检测触发器 
//        Ignore-忽略触发器 
// 返回值:在该范围内的触发器(得到了对象触发器就可以得到对象的所有信息)
colliders = Physics.OverlapSphere(Vector3.zero, 5, 1 << LayerMask.NameToLayer("Default"));

// 另一个API 
// 返回值:碰撞到的碰撞器数量
// 参数:传入一个数组进行存储
// Physics.OverlapSphereNonAlloc
if (Physics.OverlapSphereNonAlloc(Vector3.zero, 5, colliders) != 0) { }

(三)胶囊范围检测

// 3.胶囊范围检测
// 参数一:半圆一中心点
// 参数二:半圆二中心点
// 参数三:半圆半径
// 参数四:检测指定层级(不填检测所有层)
// 参数五:是否忽略触发器 不填使用UseGlobal
//        UseGlobal-使用全局设置 
//        Collide-检测触发器 
//        Ignore-忽略触发器 
// 返回值:在该范围内的触发器(得到了对象触发器就可以得到对象的所有信息)
colliders = Physics.OverlapCapsule(Vector3.zero, Vector3.up, 1, 1 << LayerMask.NameToLayer("UI"),
                                   QueryTriggerInteraction.UseGlobal);

// 另一个API 
// 返回值:碰撞到的碰撞器数量
// 参数:传入一个数组进行存储
// Physics.OverlapCapsuleNonAlloc
if (Physics.OverlapCapsuleNonAlloc(Vector3.zero, Vector3.up, 1, colliders) != 0) { }

三、射线检测

​ 例如以下的碰撞检测:

  1. 鼠标选择场景上一物体

  2. FPS 射击游戏(无弹道-不产生实际的子弹对象进行移动)

​ 等等,需要判断一条线和物体的碰撞情况如何实现呢?

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

(一)射线

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

// Ray中的参数
print(r.origin);     // 起点
print(r.direction);  // 方向

// 摄像机发射出的射线
// 得到一条从屏幕位置作为起点
// 摄像机视口方向为 方向的射线
Ray r2 = Camera.main.ScreenPointToRay(Input.mousePosition);

​ 注意:

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

(二)碰撞检测

​ Physics 类中提供了很多进行射线检测的静态函数,他们有很多种重载类型

​ 我们只需要掌握核心的几个函数,其它函数自然就明白什么意思了
​ 注意:

  • 射线检测也是瞬时的
  • 执行代码时进行一次射线检测

1.最原始的射线检测

// 准备一条射线
Ray r3 = new Ray(Vector3.zero, Vector3.forward);
// 进行射线检测 如果碰撞到对象 返回true
// 参数一:射线
// 参数二: 检测的最大距离 超出这个距离不检测
// 参数三:检测指定层级(不填检测所有层)
// 参数四:是否忽略触发器 不填使用UseGlobal
//        UseGlobal-使用全局设置 
//        Collide-检测触发器 
//        Ignore-忽略触发器 
// 返回值:bool 当碰撞到对象时 返回 true 没有 返回false
if (Physics.Raycast(r3, 1000, 1 << LayerMask.NameToLayer("Monster"), QueryTriggerInteraction.UseGlobal))
    print("碰撞到了对象");

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

2.获取相交的单个物体信息

// 物体信息类 RaycastHit
RaycastHit hitInfo;
// 参数一:射线
// 参数二:RaycastHit是结构体 是值类型 Unity会通过out 关键字 在函数内部处理后 得到碰撞数据后返回到该参数中
// 参数三:距离
// 参数四:检测指定层级(不填检测所有层)
// 参数五:是否忽略触发器 不填使用UseGlobal
//        UseGlobal-使用全局设置 
//        Collide-检测触发器 
//        Ignore-忽略触发器 
if (Physics.Raycast(r3, out hitInfo, 1000, 1 << LayerMask.NameToLayer("Monster"),
                    QueryTriggerInteraction.UseGlobal)) {
    print("碰撞到了物体 得到了信息");

    // 碰撞器信息
    print("碰撞到物体的名字" + hitInfo.collider.gameObject.name);
    // 碰撞到的点
    print(hitInfo.point);
    // 法线信息
    print(hitInfo.normal);

    // 得到碰撞到对象的位置
    print(hitInfo.transform.position);

    // 得到碰撞到对象 离自己的距离
    print(hitInfo.distance);

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

// 还有一种重载 不用传入 射线 直接传入起点 和 方向 也可以用于判断
if (Physics.Raycast(Vector3.zero, Vector3.forward, out hitInfo, 1000, 1 << LayerMask.NameToLayer("Monster"),
                    QueryTriggerInteraction.UseGlobal)) { }

3.获取相交的多个物体

// 可以得到碰撞到的多个对象
// 如果没有 就是容量为0的数组
// 参数一:射线
// 参数二:距离
// 参数三:检测指定层级(不填检测所有层)
// 参数四:是否忽略触发器 不填使用UseGlobal
//        UseGlobal-使用全局设置 
//        Collide-检测触发器 
//        Ignore-忽略触发器 
RaycastHit[] hits = Physics.RaycastAll(r3, 1000, 1 << LayerMask.NameToLayer("Monster"),
                                       QueryTriggerInteraction.UseGlobal);
for (int i = 0; i < hits.Length; i++) print("碰到的所有物体 名字分别是" + hits[i].collider.gameObject.name);

// 还有一种重载 不用传入 射线 直接传入起点 和 方向 也可以用于判断
// 之前的参数一射线 通过两个点传入
hits = Physics.RaycastAll(Vector3.zero, Vector3.forward, 1000, 1 << LayerMask.NameToLayer("Monster"),
                          QueryTriggerInteraction.UseGlobal);

// 还有一种函数 返回的碰撞的数量 通过out得到数据
if (Physics.RaycastNonAlloc(r3, hits, 1000, 1 << LayerMask.NameToLayer("Monster"),
                            QueryTriggerInteraction.UseGlobal) > 0) { }

(三)注意问题

// 注意:
// 距离、层级两个参数 都是int类型
// 当我们传入参数时 一定要明确传入的参数代表的是距离还是层级
// 举例
// 这样写是错误的 因为第二个参数 代表的是距离 不是层级
if (Physics.Raycast(r3, 1 << LayerMask.NameToLayer("Monster"))) { }
              QueryTriggerInteraction.UseGlobal) > 0) { }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/651176.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何使用Jmeter进行http接口测试?

目录 前言&#xff1a; 一、开发接口测试案例的整体方案&#xff1a; 二、接口自动化适用场景&#xff1a; 三、接口测试环境准备 四、创建工程&#xff1a; 总结&#xff1a; 前言&#xff1a; 本文主要针对http接口进行测试&#xff0c;使用Jmeter工具实现。 Jmter工具设…

HTMLCSS Day08 CSS transition过渡

文章目录 CSS过渡-Transitions-过渡三要素-过渡触发-transition-property 规定应用过渡的 CSS 属性的名称。-transition-duration 定义过渡效果花费的时间。默认是 0。-transition-timing-function 规定过渡效果的时间曲线。默认是 "ease"。-transition-delay 规定过…

史上最全文件类型读写库大盘点!什么?还包括音频、视频?

介绍史上最全PYTHON文件类型读写库大盘点&#xff01;包含常用和不常用的大量文件格式&#xff01;文本、音频、视频应有尽有&#xff01;废话不多说&#xff01;走起来&#xff01; 先给大家快捷总结&#xff1a; 文件格式Python库文本文件内置open函数CSV文件csvJSON文件jso…

信号量实现线程同步代码

信号量&实现线程同步代码 信号量线程同步示例代码 信号量 信号量&#xff08;Semaphore&#xff09;是一种用于多线程编程中的同步工具&#xff0c;用于管理对共享资源的访问。它可以控制同时访问某个资源的线程数量&#xff0c;并提供了对共享资源的互斥访问。 信号量通…

一个支持WinForms换肤的开源组件

博主介绍&#xff1a; &#x1f308;一个10年开发经验.Net老程序员&#xff0c;微软MVP、博客专家、CSDN/阿里云 .Net领域优质创作者&#xff0c;专注于.Net领域知识、开源项目分享&#xff01;&#x1f308; &#x1f6d5;文末获取&#xff0c;加入交流群&#x1f6d5; &#…

java数组(Array)

文章目录 一维数组的使用数组的长度数组元素的引用一维数组的遍历一维数组内存分析 数组元素的默认值多维数组的使用静态初始化动态初始化数组的长度和角标二维数组的遍历内存解析 Arrays工具类的使用 一维数组的使用 int[] arr; int arr1[]; double[] arr2; String[] arr3; …

网工内推 | 1-3年经验,思科、华为、华三厂商认证均可

01 地球村股份有限公司 招聘岗位&#xff1a;网络工程师 职责描述&#xff1a; 1、提供技术支持服务&#xff0c;提供设备的告警信息的分析处理及与故障问题定位服务&#xff1b; 2、及时响应在服务时限内完成处理设备故障&#xff0c;包括用户有线无线接入故障、系统故障处理…

数据库第四章(数据库安全性)

1.数据库安全性概述 disiz行 不安全因素&#xff1a; 1.非授权的用户对数据的恶意存取和破坏 2.数据库重要信息泄露 3.数据库环境的脆弱性 如何实现安全控制&#xff1f; 1.用户身份鉴别 口令鉴别 生物鉴别 2.存取控制 3.自主存取控制方法 4.授权与收回 grant and revok…

Map容器(Java)

文章目录 1.容器介绍1.1 容器接口结构1.2 简单解析 2. 容器创建(Member functions)3. 访问操作(Element access)3.1 keySet()3.2 entrySet() 4. 修改操作(Modifiers)4.1 put()4.2 remove()4.3 clear() 5. 容量操作(Member functions)5.1 size()5.2 isEmpety() 6. 其他操作(Othe…

用Swagger生成接口,pom中少了一个library参数,排查了几个小时

前言&#xff1a; 我们一般都会使用swagger生成restful接口&#xff0c;这样可以省不少时间&#xff0c;将更多的精力专注于写业务上。但接口也不是经常写&#xff0c;所以&#xff0c;swagger用的也不熟练。尤其是我喜欢拿之前的接口copy一份&#xff0c;然后在此基础上进行修…

1、springcloud环境搭建

目录 1、创建一个父项目 ​编辑 2、创建子项目 2.1创建订单系统-order ​编辑 2.2创建库存系统-stock 3、创建rest服务 3.1添加web依赖 3.2编写controller 3.3订单中需要调用库存中的扣减库存的接口 通过idea开发工具进行搭建 1、创建一个父项目 通过spring initializr…

QT day4 (time/tcp/draw)

如图所示设计一个闹钟 1、头文件 #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QColor> #include <QDebug> #include <QMessageBox> #include <QTimer> //定时器类的头文件 #include <QTime> …

搞定剑桥面试数学题番外篇2:使用多线程并发“加强版”

0. 概览 我们在之前三篇博文中已经介绍了如何用多种语言&#xff08;ruby、swift、c、x64 汇编和 ARM64 汇编&#xff09;实现一道“超超超难”的剑桥数学面试题&#xff1a; 有趣的小实验&#xff1a;四种语言搞定“超超超难”剑桥面试数学题 搞定“超超超难”剑桥面试数学…

【每日挠头算法题(7)】对称的二叉树|二叉树的所有路径

欢迎&#xff01; 前言一、对称的二叉树思路&#xff1a;递归法具体代码如下&#xff1a; 二、二叉树的所有路径思路&#xff1a;递归法具体代码如下&#xff1a; 总结 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 例如&#xff1a;随着人工智能的不…

如何快速选择合适的会计软件?这些推荐值得尝试!

现今&#xff0c;许多公司都在使用会计软件来管理它们的财务&#xff0c;提高工作效率。因此选择一个适合自己公司的会计软件是相当重要的。但是&#xff0c;对于许多小型企业而言&#xff0c;如何选择最适合自己的会计软件并不容易。那么&#xff0c;该如何选择合适的会计软件…

开启跨平台之旅:学习Flutter,掌握移动应用开发的未来

Flutter是一种开源的移动应用开发框架&#xff0c;由Google开发和维护。它使用Dart语言进行编写&#xff0c;并提供了丰富的UI组件和工具&#xff0c;用于构建高性能、跨平台的移动应用程序。 优势 跨平台开发&#xff1a;Flutter是一种跨平台的移动应用开发框架&#xff0c;…

管理类联考——英语——技巧篇——时态表

一般现在时 1.概念&#xff1a;经常、反复发生的动作或行为及现在的某种状况。 2.基本结构&#xff1a;①is/am/are;②do/does否定形式&#xff1a;①am/is/are not;②此时态的谓语动词若为行为动词&#xff0c;则在其前加don‘t&#xff0c;如主语为第三人称单数&#xff0c…

资深测试总结,性能测试-业务量/吞吐量/存量数据设计关联(详细)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 业务量 是不带时…

HTML | html文档中html和body标签的默认尺寸是多少?

新建一个空白的html文件&#xff0c;如下&#xff1a; <!DOCTYPE html> <html lang"en"><head><title></title><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-sc…

day56|动态规划16-编辑距离问题

583. 两个字符串的删除操作 明确dp数组的含义&#xff1a; dp[i][j] 以i-1为结尾的word1和以j-1为结尾的word2&#xff0c;为相同的最小操作次数递归函数&#xff1a; if word1[i-1] word1[j-1]: dp[i][j] dp[i-1][j-1] # 不需要删除&#xff0c;只看上一层的字符串即可 else…