‫嘿, 你好
‫欢迎回来｡
‫现在, 我们知道需要获取光标下的命中结果｡
‫在这段视频中, 我们将进一步讨论它的工作原理及其含义｡
‫因此, 我们的目标是获得光标下的命中结果并显示该位置, 我们可以通过绘制调试球体来实现这一点｡
‫我们也会学着怎么做｡
‫让我们来谈谈所谓的命中结果｡
‫在游戏中经常会想做这样的事情｡
‫我们在太空中会有一个点｡
‫我们称这个点为起点, 它有F型向量, 我们有终点位置｡
‫这也将是空间中F型向量的一个点｡
‫现在, 假设我们要从起点到终点画一条不可见的线｡
‫在我们画这条线的时候, 我们想看看在起点和终点之间是否有任何物体｡
‫如果有的话, 那么我们在空间中画的这条线会碰到那个物体｡
‫从表面上看, 当这种情况发生时, 我们称之为击中事件｡
‫现在, 当我们画一条这样的看不见的线时, 这叫做执行线跟踪｡
‫当我们击中某个东西时, 我们说我们有一个跟踪命中｡
‫现在, 如果我们命中了某个东西并得到了一个命中事件, 那么跟踪命中将信息存储在一个称为命中结果的结构体中｡
‫其类型为F命中结果｡
‫现在, F
‫hit results结构体包含了存储hit事件信息的变量, 包括作为空间中f向量的hit位置和我们击中的actor, 以及其他信息｡
‫现在, 当我们执行线路跟踪时, 我们通过指定冲突通道来完成｡
‫通常对于线迹, 我们选择称为可见性的通道｡
‫存在一个称为E碰撞通道的枚举, 在该枚举中有一个称为XY可见性的枚举常量｡
‫这是我们在执行线路跟踪时指定的参数之一｡
‫现在, 如果我们指定可见性通道,
‫这意味着在其碰撞设置中设置为阻止可见性通道的对象将注册碰撞事件｡
‫任何未设置为阻止可见性通道的对象都不会生成点击事件｡
‫现在, 我们希望跟踪结果位于光标下｡
‫想象一下, 我们有一个屏幕, 这是我们的光标｡
‫当我们使用函数获取光标下的命中结果时, 在光标的尖端, 我们在屏幕上有一个点｡
‫我们有一个摄像机, 它可以看到世界上的一些物体, 比如这里的地板｡
‫我们在屏幕上对应于光标位置的点上用摄像机进行一次直线跟踪, 我们将直线跟踪直接拍摄到世界上｡
‫如果我们命中了某个东西, 我们会生成一个命中事件, 并将信息存储在一个命中结果结构体中｡
‫让我们来看看如何做到这一点｡
‫我现在在坦克CP中, 我想做的是获得每一帧光标下的命中结果, 这意味着我们需要tick函数｡
‫我们再一次回到base, 在这里找到tick函数.
‫现在我们没有在基本兵中使用它, 所以我们可以把这个函数移到坦克类中, 就像我们开始游戏中所做的那样｡
‫所以我要突出显示函数声明及其注释, 然后复制它｡
‫之后我会删除这一整段, public和all, 然后我会回到H, 在public部分,
‫我会粘贴tick函数声明.
‫现在我们不用在基本兵中使用它, 所以我将从基本兵中删除tick函数｡
‫CP现在它从基本兵消失了｡
‫现在我们已经在这里声明了intent, 但是我们还需要在tank中定义函数｡
‫CP我将在tank DHCP中进行此操作, 就在setup player input component下.
‫所以我们会说是无效的｡
‫它需要一个称为Delta Time的浮点数｡
‫这是我们的身体
‫现在, 我们再次需要一个tank, 它位于tick函数之前, 沿着带有范围解析操作符｡
‫我们还需要调用超级分笔成交点并传入Delta时间｡
‫所以我们现在有了坦克类的滴答声｡
‫我们要做的是获取光标下的命中结果｡
‫所以我们是这样做的｡
‫我们要使用的函数存在于播放器控制器上, 名为get hit result under cursor｡
‫我们一直在讨论这个｡
‫下面是语法｡
‫它需要一个跟踪通道｡
‫记住, 我们需要指定一个跟踪通道, 我们将使用可见性｡
‫现在我们有两个额外的输入参数｡
‫第一个是一个称为B trace complex的布尔值｡
‫我们一会儿再讨论这意味着什么｡
‫并且第三输入参数是F命中结果｡
‫现在, 我将单击“F hit result”, 以便在文档中查看此类型｡
‫如果我向下滚动, 我们会看到一些变量｡
‫其中一个叫演员, 它的描述是演员被痕迹击中｡
‫我们还有这个B阻塞命中, 它表示这个命中是否是阻塞冲突的结果｡
‫现在, 在其他变量中, 我们有像撞击点这样的东西｡
‫这是我们在太空中实际撞击到的位置｡
‫那么我们为什么不继续尝试调用这个函数呢？
‫我们首先要我们的球员, 控制器, 感谢我们在这里所做的, 并开始发挥, 我们有球员, 控制器,
‫裁判｡
‫现在我们要做的第一件事是检查播放器控制器ref是否有效｡
‫我们总是可以将指针传递到if语句中｡
‫如果指针本身不是空指针, 它将返回true｡
‫如果它是一个空指针, 它将在if语句中返回false, 我们将永远无法到达if语句的内部｡
‫在使用指针之前, 检查指针并确保它们不为空总是一个好主意｡
‫现在我们要获取播放器, 控制器引用, 我们要使用箭头操作符调用函数,
‫获取光标下的命中结果｡
‫现在, 我们可以看到弹出窗口中有三个输入参数｡
‫第一个是跟踪通道｡
‫我们将使用EA碰撞通道, 如果我们键入两个冒号, 我们将得到一个下拉菜单,
‫它显示EA碰撞通道枚举中的所有不同枚举常量｡
‫我们希望使用可见性, 因此我们将键入XY可见性以指定我们正在使用可见性通道｡
‫现在下一个参数叫做B轨迹复合体, 我们将把false传递给它.
‫现在我们将在几分钟后讨论这意味着什么｡
‫但现在我们要用false｡
‫现在对于第三个参数, 我们需要一个命中结果｡
‫这是一个F类型的结构体命中结果｡
‫现在, 如果您将鼠标悬停在上面, 您会看到F hit
‫result作为引用传入, 如看起来像“与”号的引用操作符所示｡
‫现在, 通常当你把某个东西作为一个引用传入时, 它是一个开销引用, 这意味着函数不能改变它｡
‫但这里我们传入了一个F命中结果作为非常数引用｡
‫这通常是一个提示, 表明函数被设计为直接更改此输入参数｡
‫get hit result under cursor要做的是用关于命中结果的信息填充命中结果中的那些变量｡
‫这意味着我们需要传递这些f命中结果中的一个｡
‫我们将在if检查中创建一个局部变量, 类型为F hit result.
‫我们可以调用这个hit结果, 我们可以简单地将这个N作为第三个输入参数传递｡
‫现在, 在我们调用了这个函数之后, 这个命中结果将被填充关于这条线路的数据｡
‫例如, 我们可以访问hit result dot actor以获取被击中的演员, 或者访问dot
‫impact point以获取空间中发生击中事件的点｡
‫因此, 命中结果是我们将用来获取有关线路跟踪的信息｡
‫现在, 通常能够看到线跟踪的结果是很好的｡
‫我们可以通过绘制一个调试球体来轻松地可视化线路跟踪的结果｡
‫调试球体是我们在空间中绘制的简单形状, 它们非常适合显示位置, 我们在调试时使用它们｡
‫我们在移位游戏中并不使用调试球体｡
‫让我们看看如何画出这些调试球体｡
‫下面是一个名为draw debug sphere的函数的文档｡
‫它存在于绘图调试帮助程序中｡
‫因此, 我们可以复制这个头文件, 并将其包含在任何我们想调用draw debug sphere的地方｡
‫现在看一下所有的输入参数｡
‫首先, 它需要一个世界, 这样它就知道在哪个世界中绘制球体｡
‫它采用F向量作为球体的中心, 并采用浮点数作为半径｡
‫该球体的分段数为N 32｡
‫分段越多, 球体越圆, 其颜色为F｡
‫这样它就知道用哪种颜色来绘制这个球体｡
‫它想知道您是否需要持久性行｡
‫换句话说, 这些线条是应该立即消失还是应该继续存在？
‫如果它们确实持续存在, 则它希望知道球体的生存期｡
‫何时应该停止绘制球体？
‫如果你不画持久性的线, 比如说你想画一个帧, 那么你会把负1作为生存期｡
‫最后两个参数是可选的, 因此我们将通过只讨论前七个参数来保持简单｡
‫让我们来看看这是如何工作的｡
‫我将在顶部绘制一个调试球体, 我将包括绘制调试助手｡
‫这就是这个draw debug sphere函数的声明位置｡
‫现在, 让我们开始玩, 只是简单地画一个调试球体, 看看它是如何工作的｡
‫所以我要调用draw debug sphere和｡
‫第一个输入参数是新世界｡
‫我们可以在任何时候通过调用Get World来获取我们的世界, Get World返回一个指向我们当前世界的新世界指针｡
‫这样就满足了第一个输入｡
‫接下来, 我们需要一个f向量来表示球的中心｡
‫现在我们调用这个函数并开始播放, 这样我就可以简单地调用get actor location,
‫这样就可以得到我们的水池的位置｡
‫因为我们在坦克课上｡
‫现在我要把球体抬高一点｡
‫所以我要加上一个向量, x的零点是F, Y的零点是F, Z的零点是200｡
‫现在, 我将把这些输入参数分别放在各自的行上｡
‫所以很清楚我们为每个输入传递了什么｡
‫第二个输入是获得这个表达式, 它是演员位置, 加上一个向上指向的向量, 长度为200｡
‫将这两个向量相加, 给予可以得到坦克在Z轴上升高200个单位的位置｡
‫现在是下一个输入参数, 它是球体的半径｡
‫我将选择100 F, 这样我们就可以看到半径为100的调试球体是什么样子的｡
‫接下来是段数｡
‫我选12｡
‫我们来看看会是什么样子｡
‫对于F颜色, 存在一个F颜色类, 它内置了很多颜色, 如红色｡
‫现在对于布尔值B持久性行, 我选择true｡
‫对于下一个输入参数, 我们有生存期通知｡
‫它的默认值为负1｡
‫这意味着默认情况下, 它将为单个帧绘制调试球体｡
‫但我会传入30 F, 这样我们就得到了30秒的球体, 我可以省略最后两个参数｡
‫这是我们用来绘制调试球体的函数调用｡
‫让我们编译一下, 看看它是什么样子的｡
‫好吧, 我又回到编辑部了｡
‫我将打开第二个窗口, 这样我们就可以在全屏中看到它｡
‫我可以转到窗口视口并选择视口2, 现在我看到了第二个窗口｡
‫它打开时可能不是全屏, 但您始终可以将其最大化｡
‫现在我可以用alt p玩这个游戏了｡
‫现在看看这个
‫这是我们的调试球体｡
‫注意它并不完全是圆的｡
‫我们选择了12个段｡
‫选择的分段越多, 绘制球体所需的线就越多｡
‫这是一个半径为100的球体｡
‫它相当大, 球体的中心在坦克的位置, 加上200个单位在空中｡
‫这就是我们绘制调试球体的方法｡
‫因此, 您面临的挑战是使用光标下的跟踪结果绘制一个调试球体｡
‫因此, 在我们的新if语句中绘制一个调试球体, 我们将在其中检查播放器控制器ref是否不为空｡
‫现在使用我们的命中结果, 从命中结果中获得撞击点, 并将其作为球体的中心｡
‫现在, 对于持久性线输入参数, 使用false, 对于持续时间, 使用负1｡
‫这将导致在一个帧中绘制球体, 这是可以的, 因为我们在tic函数中调用了每一帧｡
‫因此, 暂停视频并在tick函数中绘制调试球体｡
‫好吧, 我会的
‫所以我回到了坦克｡
‫现在, 我在这里调用了这个draw debug sphere函数,
‫并开始播放, 这样我就可以继续复制它, 并将其从开始播放中删除, 我们将返回到if语句中的tick,
‫我将其粘贴到这里, 并更改一些输入参数｡
‫首先, 我们改变了球心的位置｡
‫我们将使用命中结果｡
‫所以我会说命中结果是点撞击点｡
‫至于半径, 我想把它做得小一点｡
‫那就25块吧
‫没关系, 我会的
‫如果不是你干的, 我就干这个｡
‫所以球体并不是那么大｡
‫现在, 我们传递的倒数第二个参数是持久性行｡
‫我将传入false, 对于持续时间, 而不是30秒, 我将使用负一点F.
‫这样我们就得到了一个单帧的球体, 这是好的, 我们在tick函数中调用了这个,
‫所以我们会在每一帧都调用它｡
‫让我们继续进行编译｡
‫现在, 回到编辑器中｡
‫如果我现在按播放, 看看这个｡
‫我有一个调试球体, 它被绘制在光标下的线跟踪的影响点｡
‫现在, 我们可以将其移到墙壁和其他对象上, 轨迹会碰到这些对象, 因为它们被设置为阻挡可见性通道｡
‫现在很棒｡
‫我答应过我们会讨论复杂追踪和简单追踪的区别｡
‫我们玩游戏的时候我给你看点东西｡
‫让我们在视口中单击, 以便可以控制手掌｡
‫现在, 按波浪号键并键入控制台命令show collision｡
‫现在在我的屏幕上可能不那么容易看到, 但你绝对可以在你的屏幕上看到｡
‫注意我们的兵的碰撞｡
‫我们不仅可以看到太空舱, 还可以看到坦克和炮塔网格周围的碰撞体积｡
‫这是简单的碰撞｡
‫让我给你们看一个简单的碰撞｡
‫我将进入资产和网格, 如果我双击, 比如说, 坦克基地, 我们将看到复杂的碰撞｡
‫如果我点击顶部的显示图标, 选择复杂碰撞, 我可以看到复杂碰撞中的所有多边形,
‫而且有很多多边形｡
‫如果我再次单击显示图标, 并且这次选中“简单碰撞”（Simple Collision）旁边的复选框, 请注意会出现另一个碰撞体积｡
‫这被称为碰撞船体, 它的几何体要少得多｡
‫具有该碰撞体积的多边形数量较少｡
‫这是物理引擎用来检测命中事件中重叠的内容｡
‫如果使用复杂碰撞, 需要的计算量会大得多｡
‫这就是为什么我们有简单的碰撞体积, 所以它的性能更好, 无论何时做一个线跟踪,
‫如果我们跟踪简单的碰撞, 而不是复杂的碰撞｡
‫现在我们已经得到了光标下的命中结果｡
‫我们花了一些功夫才做到这一点, 但现在我们有了它, 我们已经通过用调试球体显示这个位置来证明它｡
‫这是一个很好的方式来确认我们的跟踪命中是工作｡
‫现在我们知道它起作用了, 我们可以用这个位置来旋转坦克上的炮塔｡
‫我们会在下一个视频中做这个｡
‫我很快就会见到你的｡