Unity笔记(九)——画线功能Linerenderer、范围检测、射线检测

写在前面:

写本系列(自用)的目的是回顾已经学过的知识、记录新学习的知识或是记录心得理解,方便自己以后快速复习,减少遗忘。这里只记录代码知识。

十一、画线功能Linerenderer

画线功能Linerenderer是Unity提供的画线脚本,创建一个空物体,在Inspector页面添加Line Renderer脚本,即可开启画线功能。面板里有一系列参数,用于控制画线等,这里仅对代码控制面板参数进行介绍。

我们可以使用之前学过的创建物体并挂载脚本的方法来创建line物体并为其挂载Line Renderer脚本:GameObject line = new GameObject();
line.name = "Line";
LineRenderer lineRenderer = line.AddComponent<LineRenderer>();

接着我们就可以使用一系列API来设置线条的参数:

是否设置线条首尾相连:lineRenderer.loop = true;表示首位相连,false不会自动首尾相连。

设置线条的开始结束宽

     lineRenderer.startWidth = 0.02f;设置线条开始的宽为0.02
lineRenderer.endWidth = 0.02f;设置线条的结束宽为0.02

设置线条的开始结束颜色
lineRenderer.startColor = Color.white;设置线条开始颜色为白色
lineRenderer.endColor = Color.red;设置线条结束颜色为红色

设置线条材质
m = Resources.Load<Material>("M");动态加载线条材质
lineRenderer.material = m;设置线条材质

设置线条中的点
lineRenderer.positionCount = 4; 设置线条有4个点
lineRenderer.SetPositions(new Vector3[] { new Vector3(0, 0, 0),
new Vector3(0, 0, 5),
new Vector3(5, 0, 5)});批量设置三个点

    lineRenderer.SetPosition(3, new Vector3(5, 0, 0));单独设置索引为3的点(第四个点)

设置世界坐标系:即是否随对象移动而移动
lineRenderer.useWorldSpace = false;当设置世界坐标系为false时,线条会跟随对象移动而移动,反之不会

 设置线段是否受光的影响:若设置为true,会接收光的数据进行着色器计算
lineRenderer.generateLightingData = true;

private Material m;void Start()
{//动态添加一个线段GameObject line = new GameObject();line.name = "Line";LineRenderer lineRenderer = line.AddComponent<LineRenderer>();//首尾相连lineRenderer.loop = true;//开始结束宽lineRenderer.startWidth = 0.02f;lineRenderer.endWidth = 0.02f;//开始结束颜色lineRenderer.startColor = Color.white;lineRenderer.endColor = Color.red;//设置材质m = Resources.Load<Material>("M");lineRenderer.material = m;//设置点lineRenderer.positionCount = 4;lineRenderer.SetPositions(new Vector3[] { new Vector3(0, 0, 0),new Vector3(0, 0, 5),new Vector3(5, 0, 5)});lineRenderer.SetPosition(3, new Vector3(5, 0, 0));//是否设置世界坐标系,即是否随对象移动而移动lineRenderer.useWorldSpace = false;//让线段受光的影响,会接收光的数据进行着色器计算lineRenderer.generateLightingData = true;
}

十二、核心系统

1、范围检测

范围检测主要用于瞬时的碰撞检测。想要被范围检测到的对象,必须具备碰撞器。范围检测相关API,只有当真正执行该句代码时,进行一次范围检测,它是瞬时的。并且,它不会真正产生一个碰撞器,只是碰撞判断计算而已。

(1)盒状范围检测

盒装范围检测使用的API是:Physics.OverlapBox()。

括号内表示位置的参数有三个:参数一,立方体中心点;参数二,立方体三边大小的一半;参数三,立方体的角度。参数一、二均为Vector3类型变量,参数三为一个四元数。

可选传入的其他参数有两个:参数四,检测指定层级,不填检测所有层;参数五,是否忽略触发器。其中,UseGlobal使用全局设置、Collide检测触发器、IIgnore忽略触发器,不填默认使用UseGlobal。

现在解释一下这两个参数:

首先是参数四检测指定层级,该参数需要传入的是指定层级的编号的二进制。将层级名转为十进制编号使用API:LayerMask.NameToLayer(),在括号内传入层级的名字,例如LayerMask.NameToLayer("UI"),输出的就是一个int值,表示UI层级十进制编号。

那么层级二进制是如何编号的呢?这里需要补充一下。Unity中层级最多设置32层,int值刚好是32bit,也就是由32位二进制组成。

层级0:0000 0000 0000 0000 0000 0000 0000 0001

层级1:0000 0000 0000 0000 0000 0000 0000 0010

....

层级31:1000 0000 0000 0000 0000 0000 0000 0000

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

那么参数四可以这样传入:1 << LayerMask.NameToLayer("UI"),解释一下就是,1的二进制为:0000 0000 0000 0000 0000 0000 0000 0001,UI是层级5,左移五位就为:0000 0000 0000 0000 0000 0000 0010 0000。那么,当你希望可以检测多个层级时,就可以用与运算:1 << LayerMask.NameToLayer("UI") | 1 << LayerMask.NameToLayer("Default")

现在来介绍参数五:参数五使用QueryTriggerInteraction,可以通过点来选择是否忽略触发器: 传入QueryTriggerInteraction.UseGlobal表示使用全局触发器设置。全局触发器设置的查看方式是:Edit——Project Settings

返回值:在该范围内的触发器(得到了对象的触发器就可以得到对象的所有信息)。下面是代码实例:

void Start()
{//盒状范围检测Collider[] colliders = Physics.OverlapBox(Vector3.zero, Vector3.one, Quaternion.AngleAxis(45, Vector3.up),1 << LayerMask.NameToLayer("UI") | 1 << LayerMask.NameToLayer("Default"),QueryTriggerInteraction.UseGlobal);for(int i = 0; i < colliders.Length; i++){print(colliders[i].gameObject.name);}
}

这样,就创建了一个盒状范围检测器,当有物体进入这个范围时,就会瞬间检测碰撞。

此外,盒装检测器还可以使用另外一个API:

void Start()
{if(Physics.OverlapBoxNonAlloc(Vector3.zero, Vector3.one, colliders)!= 0){}
}

Physics.OverlapBoxNonAlloc(),与先前所说的API不同的是,Physics.OverlapBoxNonAlloc()必须传入的第三个参数是一个数组,它会直接将在该范围内的触发器填入这个数组,返回该数组的长度(触发器个数)。

(2)球状范围检测

和(1)几乎一致:
参数一,中心点位置;参数二,球半径;参数三,检测对应层级;参数四,是否忽略触发器。

返回值:在该范围内的触发器

void Start()
{colliders = Physics.OverlapSphere(Vector3.zero, 5,1 << LayerMask.NameToLayer("Default"),QueryTriggerInteraction.UseGlobal);if(Physics.OverlapSphereNonAlloc(Vector3.zero, 5, colliders)!=0){}
}

(2)胶囊范围检测

和(1)几乎一致:

参数一,半圆中心点1;参数二,半圆中心点2;参数三,半径;参数四,检测对应层级;参数五,是否忽略触发器。

半圆中心点1、2如图:

返回值:在该范围内的触发器

void Start()
{colliders = Physics.OverlapCapsule(Vector3.zero, Vector3.up, 1, 1 << LayerMask.NameToLayer("Default"),QueryTriggerInteraction.UseGlobal);if(Physics.OverlapCapsuleNonAlloc(Vector3.zero,Vector3.up, 1,colliders) !=0){}
}

2、射线检测

射线检测,在FPS游戏中有重要意义。例如枪发射子弹时,其实是进行了射线检测。”发出“一条射线,检测射线碰撞到的物体,并进行判定。

(1)射线

可以使用Ray r = new Ray()直接创建一条射线,其中参数一是起点,参数二是方向。射线创建完成后,通过r.origin可以获得起点,r.direction可以获得方向。

void Start()
{Ray r = new Ray(Vector3.right, Vector3.forward);print(r.origin);print(r.directi
}

此外,这里还有另一种创建射线的方式,利用API:ScreenPointToRay()可以将屏幕坐标转化为射线。例如希望创建摄像机发射出的射线,得到一条从屏幕位置作为起点,摄像机视口方向为方向的射线:

void Start()
{Ray r2 = Camera.main.ScreenPointToRay(Input.mousePosition);
}

(2)碰撞检测函数

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

①最原始的射线检测

最原始的射线检测是使用API:Physics.Raycast(),括号内可以传入多个参数。参数一,射线;参数二,检测的最大距离,超出这个距离不会检测;参数三,检测指定层级;参数四,是否忽略触发器。

返回值:bool,如果碰撞到对象 返回true

void Start()
{Ray r3 = new Ray(Vector3.zero, Vector3.forward);if(Physics.Raycast(r3, 1000, 1 << LayerMask.NameToLayer("Monster"),QueryTriggerInteraction.UseGlobal)){print("碰撞到了对象");}
}

此外,也可以不传入射线,直接传入射线的起点和方向:

void Start()
{ if (Physics.Raycast(Vector3.zero, Vector3.forward, 1000, 1 << LayerMask.NameToLayer("Monster"),QueryTriggerInteraction.UseGlobal)){print("碰撞到了对象2");}
}
②能获取相交的单个对象的射线检测

①提到的射线检测只能得到射线是否碰到了对象,不能获得对象信息。若是想获得对象信息,需要先创建一个RaycastHit变量来存储射线碰撞到的对象:RaycastHit hitInfo;

在API,Physics.Raycast()中,传入的第二个参数需要是out hitInfo,用于存储得到的碰撞对象。用out的原因是,out可以使传入的参数不需要赋值,等代码逻辑进行赋值即可。第一个参数仍然是射线。第三个参数及之后的参数不变。

得到对象后,就可以得到碰撞对象的一系列信息,都列在如下代码中:

void Start()
{RaycastHit hitInfo;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);}
}

同样的,也可以不传入射线,直接传入射线的起点和方向:

void Start()
{RaycastHit hitInfo;if (Physics.Raycast(Vector3.zero, Vector3.forward, out hitInfo, 1000, 1 << LayerMask.NameToLayer("Monster"), QueryTriggerInteraction.UseGlobal)){}
}
③获取碰撞到的多个对象

射线碰到的对象可能不止一个,因此就需要获取多个对象。获取多个对象的API是:Physics.RaycastAll(),和之前相似,传入多个参数:射线、检测距离、检测层级、是否忽略触发器。返回值是一个RaycastHit数组:

void Start()
{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);}
}

同样的,不传入射线,直接传入起点和方向也可以:

void Start()
{hits = Physics.RaycastAll(Vector3.zero, Vector3.forward, 1000, 1 << LayerMask.NameToLayer("Monster"), QueryTriggerInteraction.UseGlobal);
}

至此,基础部分结束了。

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

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

相关文章

刷题记录(8)string类操作使用

一、仅反转字母 917. 仅仅反转字母 - 力扣&#xff08;LeetCode&#xff09; 简单来说输入字符串&#xff0c;要求你返回所有仅字母位置反转后的字符串。 简单看一个样例加深理解&#xff1a; 前后互换&#xff0c;我想思路基本很明显了&#xff0c;双指针&#xff0c;或者说…

用好AI,从提示词工程到上下文工程

前言 随着 AI 大模型的爆发,提示词工程(prompt engineering ) 一度是用户应用 AI ,发挥 AI 能力最重要、也最应该掌握的技术。 但现在,在 “提示词工程”的基础上,一个更宽泛也更强力的演化概念被提出,也就是本文我们要介绍的 “上下文工程(Context Engineering)” …

计算机Python毕业设计推荐:基于Django+Vue用户评论挖掘旅游系统

精彩专栏推荐订阅&#xff1a;在下方主页&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f496;&#x1f525;作者主页&#xff1a;计算机毕设木哥&#x1f525; &#x1f496; 文章目录 一、项目介绍二、…

⸢ 肆 ⸥ ⤳ 默认安全:安全建设方案 ➭ a.信息安全基线

&#x1f44d;点「赞」&#x1f4cc;收「藏」&#x1f440;关「注」&#x1f4ac;评「论」 在金融科技深度融合的背景下&#xff0c;信息安全已从单纯的技术攻防扩展至架构、合规、流程与创新的系统工程。作为一名从业十多年的老兵&#xff0c;将系统阐述数字银行安全体系的建设…

如何用AI视频增强清晰度软件解决画质模糊问题

在视频制作和分享过程中&#xff0c;画质模糊、细节丢失等问题常常影响观看体验。无论是老旧视频的修复还是低分辨率素材的优化&#xff0c;清晰度提升都成为用户关注的重点。借助专业的AI技术&#xff0c;这些问题可以得到有效解决。目前市面上存在多种解决方案&#xff0c;能…

Linux92 shell:倒计时,用户分类

问题 while IFS read -r line;doootweb kk]# tail -6 /etc/passwd user1r4:x:1040:1040::/home/user1r4:/bin/bash useros20:x:1041:1041::/home/useros20:/bin/bash useros21:x:1042:1042::/home/useros21:/bin/bash useros22:x:1043:1043::/home/useros22:/bin/bash useros23…

LinkedList源码解析

1. 数据结构设计 (1) 节点结构 LinkedList 的核心是双向链表节点 Node&#xff1a; private static class Node<E> {E item; // 存储的元素Node<E> next; // 后继节点Node<E> prev; // 前驱节点Node(Node<E> prev, E element, Node<E&g…

语雀批量导出知识库

使用工具&#xff1a;yuque-dl 参考文档&#xff1a; GitHub - gxr404/yuque-dl: yuque 语雀知识库下载 Yuque-DL&#xff1a;一款强大的语雀资源下载工具_语雀文档怎么下载-CSDN博客

电子电气架构 --- 当前企业EEA现状(下)

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 做到欲望极简,了解自己的真实欲望,不受外在潮流的影响,不盲从,不跟风。把自己的精力全部用在自己。一是去掉多余,凡事找规律,基础是诚信;二是…

flink中的窗口的介绍

本文重点 无界流会源源不断的产生数据,有的时候我们需要把无界流进行切分成一段一段的有界数据,把一段内的所有数据看成一个整体进行聚合计算,这是实现无界流转成有界流的方式之一。 为什么需要窗口 数据是源源不断产生的,我们可能只关心某个周期内的统计结果。比如电费…

自建es 通过Flink同步mysql数据 Docker Compose

资源es:7.18 kibana:7.18 flink:1.17.2目录mkdir -p /usr/project/flink/{conf,job,logs} chmod -R 777 /usr/project/flink #资源情况 mysql8.0 Elasticsearch7.18 自建# 目录结构 /usr/project/flink/ /usr/project/flink/ ├── conf/ │ ├── flink-conf.yaml │ └…

AI浏览器和钉钉ONE是不是伪需求?

最近两则新闻格外引起了我的注意&#xff1a;一是Claude推出了官方浏览器插件&#xff0c;二是钉钉发布了钉钉ONE。前者说明AI浏览器未必有必要&#xff0c;后者则描绘了一幅“刷刷手机就能完成工作”的未来办公图景。这几天我经常在思考&#xff0c;AI浏览器是不是没有必要&am…

从结构化到多模态:RAG文档解析工具选型全指南

在RAG系统建设中&#xff0c;文档解析质量直接决定最终效果上限&#xff0c;选择合适的解析工具已成为避免"垃圾进&#xff0c;垃圾出"&#xff08;GIGO&#xff09;困境的关键决策。一、文档解析&#xff1a;RAG系统的基石与瓶颈 当前企业知识库中超过80%的信息存储…

设计模式:享元模式(Flyweight Pattern)

文章目录一、享元模式的介绍二、实例分析三、示例代码一、享元模式的介绍 享元模式&#xff08;Flyweight Pattern&#xff09; 是一种结构型设计模式。通过共享相同对象&#xff0c;减少内存消耗&#xff0c;提高性能。 它摒弃了在每个对象中保存所有数据的方式&#xff0c; 通…

【Go语言入门教程】 Go语言的起源与技术特点:从诞生到现代编程利器(一)

文章目录前言1. Go语言的起源与发展2. Go语言的核心设计团队2.1 Ken Thompson&#xff08;肯汤普森&#xff09;2.2 Rob Pike&#xff08;罗布派克&#xff09;2.3 Robert Griesemer&#xff08;罗伯特格瑞泽默&#xff09;设计动机&#xff1a;解决C的痛点3. Go语言的核心特性…

rocketmq启动与测试

1.更改runserver.sh的内存大小 vi runserver.sh 2.更改 runbroker.sh内存大小 vi runbroker.sh3.设置环境变量 vi ~/.bash_profile 新增 export NAMESRV_ADDRlocalhost:98764.启动 --在bin的上一级目录启动 nohup bin/mqnamesrv & nohup bin/mqbroker &5.查看日志 le…

11.《简单的路由重分布基础知识探秘》

11_路由重分布 文章目录11_路由重分布路由重分布概述路由重分布的核心作用基础实验实验流程实验拓扑配置示例(基本操作省略)实验结论路由重分布概述 路由重分布&#xff08;又称路由引入&#xff09;是指在不同路由协议之间交换路由信息的技术。在复杂网络中&#xff0c;可能同…

C++ 左值引用与右值引用介绍

C 左值引用与右值引用详解 在 C 的类型系统中&#xff0c;引用&#xff08;reference&#xff09; 是一种为已有对象起别名的机制。在早期&#xff08;C98/03&#xff09;中&#xff0c;C 只有 左值引用&#xff08;lvalue reference&#xff09;&#xff0c;主要用于函数参数…

基于物联网设计的园林灌溉系统(华为云IOT)_274

文章目录 一、前言 1.1 项目介绍 【1】项目开发背景 【2】设计实现的功能 【3】项目硬件模块组成 【4】设计意义 【5】国内外研究现状 【6】摘要 1.2 设计思路 1.3 系统功能总结 1.4 开发工具的选择 【1】设备端开发 【2】上位机开发 1.5 参考文献 1.6 系统框架图 1.7 系统原理…

uni-app iOS 应用版本迭代与上架实践 持续更新的高效流程

很多团队在使用 uni-app 开发 iOS 应用时&#xff0c;往往能顺利完成第一次上架&#xff0c;但一到 版本更新和迭代 环节&#xff0c;就会频繁遇到瓶颈&#xff1a;证书是否能复用&#xff1f;如何快速上传&#xff1f;怎样保持节奏不被打乱&#xff1f; 本文结合实战经验&…