前言
由 Epic Games 推出的虚幻系列引擎,因其高效、全能、易获取、所见即所得等特性受到广大游戏开发者的欢迎,市面上也不乏从入门到深度分析的教程。本系列主要面向虚幻引擎的初学者以及有一定实践经验的虚幻引擎游戏开发者,分享能够立即运用在自己项目中的实践技巧。本教程综合了个人的学习笔记、官方文档以及个人心得,水平不足之处,望读者反馈和指正。
本文是 UE 应用实例分享系列专栏的第五篇。
正文
射线检测(Raycast)是一种应用广泛的检测方式,类似碰撞检测,也能用于判断是否指向了某个物件。以游戏 Apex 为例:恶灵被瞄准时会得到提示;视线对准的物件会被高亮;鼠标指向的物体能被选中,等等。
在 Cocos 引擎中,射线检测被定义为:对一条射线和另一个形状进行相交性判断。而虚幻引擎则认为:射线检测是获取有关线段上存在内容的反馈的方法。
综合来讲,射线检测会发射一条由 A -> B 的射线,如果射线命中一个游戏对象,便可以获取到对象的引用、角度、位置等信息。我们可以利用这些信息来进行逻辑判断,实现 Gameplay 功能。
射线的类型:API 介绍
在蓝图中输入函数名,我们可以调用射线检测相关的 API,虚幻引擎的射线检测相关函数命名规则如下:
(前缀:Multi) + 射线形状 + [后缀:ForObjects|ByChannel|ByProfile]
- Multi(前缀):通常射线在碰到第一个对象就会失效,Multi 前缀可以使射线穿透多个对象。
- 射线形状:分为线形、球形、立方体、脚囊体等多个类型。
- 筛选方式(后缀):
- ForObjects:按照一个类类型来进行检测,包括制定的类型的所有子类。
- ByChannel:将物体和射线都指定到某一个通道来进行过滤,有 Ignore/Overlap/Block 几种选择。
- ByProfile:使一个射线的响应方式完全照搬一套预设。
案例:在蓝图使用射线检测
在这里,我们使用不带 Multi 的接口 LineTraceByChannel
,可以发射一条单独射线并检测碰到的第一个对象。
1. 第一步我们要做的就是使用蓝图创建这个节点。你可以在 Tick 每一帧都去检测,也可以在触发一些事件时进行检测。
2. 第二步给出了 Start 和 End 两个参数,分别代表射线发出位置和终止位置坐标。在本例中,我们使用角色摄像机作为出发点,镜头对准方向距离 1500 长度的位置作为终止点。
3. 第三步,处理检测产生结果。将 Out Hit
节点使用 Break Hit Result
打开,可以获取到各种各样我们需要的数据进行判断和处理。在这里我们把命中的 Actor 打印出来。
4. 实时调试相关:如果我们勾选了 Draw Debug Type
为 For One Frame
,我们可以看到引擎绘制了射线方便我们查看射线的工作情况,同时屏幕上打印了我们需要的信息。
一些说明:
- 关于 Trace Channel:用于过滤射线会命中的对象,后文会详细介绍。
- Trace Complex:物体的碰撞模型一般有简单/复杂两种,勾选会使用更精确的碰撞模型,但是会增加计算开销。
- Actors to Ignore:字面意思,传入的 Actors 会被忽略,射线不会命中。
C++ 的不同形状射线检测函数
这里主要介绍 C++ 关于射线检测部分的函数声明,刚刚的例子使用的蓝图节点最终也是通过 C++ 的这些接口来进行调用的。
LineTraceSingleByXXX
UWorld::LineTraceSingleByXXX
提供了基本的射线检测,可以绘制一条直线,返回命中的第一个对象的 HitResule。下文中提到的 SweepSingleByXXX
也是基于 LineTrace 实现。
LineTraceSingleByXXX
有三种类型,后文会详细介绍它们的区别:
LineTraceSingleByChannel
LineTraceSingleByObjectType
LineTraceSingleByProfile
完整定义参见虚幻文档:UWorld::LineTraceSingleByChannel
SweepSingleByXXX
UWorld::SweepSingleByXXX
可以射出某种形状的射线,返回这个形状碰到的第一个物体。在形状上提供 Box、Sphere、Capsule 三种选择。在 KismetSystemLibrary
中有 XxxTraceSingle
系列蓝图接口,是基于 SweepSingleByXXX
实现的,方便蓝图中使用。
同样的 SweepSingleByXXX
有三种类型:
SweepSingleByChannel
SweepSingleByObjectType
SweepSingleByProfile
这里同样附上文档:UWorld::SweepSingleByChannel
如何过滤检测的物体
如果我们不希望射线对某些物体做出反应,该如何应对呢?比如我们需要检测敌人是否被我们瞄准,但是使用角色分类却会同时命中队友和敌人。这时候我们就需要过滤射线会响应的对象。
虚幻引擎提供了三种方式来过滤射线是否会命中对象。射线检测基于碰撞检测,所以可以在 ProjectSettings -> Collision 设置 TraceChannel/ObjectChannel,这是基于碰撞检测的两种过滤方式。除了 UE 提供了几种默认的类型外,我们可以添加自定义类型,不过 Channel 数量最高只能有 18 个。
TraceChannel
在射线检测中,Trace Channel 可以帮助我们过滤对射线起作用的物体。在 Engine - Collision 菜单中可以配置 Trace Channel 的类型。在 StaticMesh 的 Detial 面板中可以设置物体对每一个 Channel 的反应。
一共有三种反应类型:
- Ignore 完全忽略射线
- Overlap 触发并穿透射线
- Block 触发并阻挡射线
查找对应 Channel 的名称需要在虚幻引擎的配置文件 DefaultEngine.ini 中搜索。
ObjectChannel
每一个对象都有一个碰撞类型,ObjectChannel 等于在碰撞设置中的 ObjectType 参数。
Profile
Profile 其实就是碰撞检测中的 Collision Presets。Collision Presets 综合利用了以上两种方式来进行判断,是很常用的过滤方式。射线的 ObjectType 以及目标物体的 ObjectType 如果被判断为 Block 那么射线就会命中。
参考资料
[1]: 简析 Unity 射线检测的概念与应用 - 知乎
[2]: 射线检测 · Cocos Creator
[3]: 虚幻引擎追踪概述 | 虚幻引擎 5.0 文档
[4]: [玩转 UE4 动画系统>基础篇] 之 什么是射线检测 - 知乎
[5]: Using a Single Line Trace (Raycast) by Channel in Unreal Engine | Unreal Engine 5.1 Documentation
[6]: 细说 UE 的碰撞与检测 | 月光林地
封面:自制
*本文内容系作者独立观点,不代表 indienova 立场。未经授权允许,请勿转载。
暂无关于此文章的评论。