‫你好, 欢迎回来｡
‫现在, 我们准备旋转炮塔, 我们想使用鼠标来完成此操作｡
‫我们在上一个视频中追踪到的位置｡
‫所以当我移动鼠标光标时, 炮塔会旋转并朝向鼠标光标的方向｡
‫而且即使我在视口中单击并开始播放, 我仍然可以四处移动鼠标光标来旋转炮塔并设置其方向｡
‫这将使我能够瞄准时, 我有能力发射炮弹｡
‫好吧, 我会的
‫所以要做到这一点, 我们需要找到我们希望炮塔指向的方向｡
‫一旦我们找到了方向, 我们就可以设置炮塔网格旋转｡
‫现在, 为了得到我们希望炮塔指向的方向, 我们需要做一些矢量数学｡
‫我们要找的是从坦克炮塔到目标位置的方位｡
‫现在我们可以很容易地得到我们的坦克或其任何组件的位置, 如坦克的炮塔的位置｡
‫我们把这个位置称为炮塔位置｡
‫而且我们也知道如何才能得到追踪头的位置｡
‫我们称之为追踪命中位置｡
‫我们感兴趣的是从炮塔位置到追踪目标位置的矢量｡
‫我们称这个向量为目标向量｡
‫现在, 通过矢量数学来达到目标实际上非常简单｡
‫要获得从起点到终点的矢量, 始终是终点减去起点｡
‫所以如果我们用我们的轨迹, 命中位置, 减去炮塔的矢量位置,
‫那么由此得到的矢量就是目标｡
‫现在, 一旦我们有了两个目标的方向向量, 我们想把它转换成一个旋转,
‫这样我们就可以设置坦克炮塔的旋转｡
‫向量类型有一个内置的函数, 称为旋转｡
‫所以如果我们取目标向量并调用rotation, 这将返回对应于该方向的F旋转器｡
‫现在我们确实需要记住一些事情｡
‫跟踪命中结果通常会在地面上, 从坦克炮塔到跟踪命中结果的矢量不会与地面平行｡
‫这意味着如果我们把坦克炮塔的旋转方向设置为我们从那个方向矢量得到的旋转方向,
‫我们可能会得到这样的结果, 炮塔朝下倾斜朝向地面, 但我们不希望坦克炮塔向下旋转｡
‫我们希望它仍然指向前方｡
‫所以这就是我们想要的结果｡
‫换句话说, 我们只想改变坦克炮塔旋转的是的分量｡
‫这样它就指向了正确的方向, 但仍然与地面保持平行｡
‫我们只改变了它的偏航角, 所以让我们跳回到VS代码, 并创建一个函数来旋转坦克炮塔｡
‫现在我们要旋转坦克上的炮塔, 但我们也想旋转我们的塔敌人上的炮塔, 塔很快就会从base
‫pon衍生出来, 这意味着如果我们创建一个旋转炮塔功能, 我们可以把它放在base
‫pong类中｡
‫这样水箱和塔都能继承这个功能｡
‫由于我们计划在塔和罐中使用它, 我们可以使此功能受到保护｡
‫所以我将添加一个protected区域, 在protected区域中放置的任何函数和变量都可以在这些子类中访问,
‫但不能在任何其他类中访问｡
‫所以它几乎和私有变量一样受限制｡
‫现在这个函数可以返回void｡
‫我把这个叫做旋转炮塔｡
‫为了转动炮塔, 我需要一个目的地｡
‫这可以是一个f向量, 我们可以称之为注视目标｡
‫如果我们有一个函数, 可以传递到世界上的某个位置,
‫那么这个函数应该会导致炮塔向那个位置旋转.
‫因此, 让我们继续, 并提供一个功能定义旋转炮塔｡
‫所以这里在基本兵CP下的构造函数中, 我要实现旋转炮塔｡
‫当然, 我需要一个基本的兵类名称和作用域解析操作符｡
‫现在我已经有了旋转炮塔, 让我们来想想我们将如何实现它｡
‫我们需要的第一件事是目标向量从炮塔组件的向量到鼠标光标下的轨迹命中结果｡
‫这可以是一个局部F向量, 我们将把它设为某个向量数学的结果｡
‫记住, 这将是目的地减去起点｡
‫目的地是观察目标, 而起点是坦克炮塔的位置, 换句话说,
‫就是炮塔的位置.
‫因此, 我们可以说炮塔网格, 我们可以得到炮塔网格的位置｡
‫现在, 获取组件的全局位置的方法是使用此函数获取组件位置｡
‫它属于使用场景组件类｡
‫所以所有场景组件都有它｡
‫因此, 从炮塔网格, 我们将调用获取组件位置｡
‫因此, 观察目标减去炮塔网格位置, 得到了从炮塔网格到观察目标的矢量｡
‫现在, 正如我提到的, 我们可以使用F向量旋转函数获得从目标到目标的EF旋转器｡
‫所以我们要做一个F旋转器, 我们可以称之为注视旋转, 我们将它设置为等于目标点旋转｡
‫这是一个函数调用｡
‫现在我们有了对应于这个目标方向向量的旋转器｡
‫但问题是我们只关心雅｡
‫我们不想改变音高或角色｡
‫我们只想绕z轴旋转炮塔, 并保持它与地面平行｡
‫现在我们可以用很多种方法来做｡
‫首先, 我们可以看看旋转, 俯仰和调零｡
‫换句话说, 将其设置为零｡
‫我们也可以看看旋转点的作用, 并将其归零｡
‫现在, 当我们将俯仰和滚转设置为零后, 我们就得到了想要的旋转, 这只是一个分量｡
‫这是一种方法｡
‫另一种方法是使用F旋转器构造函数重载之一｡
‫如果我们用圆括号表示f旋转器, 并传入一些值, 如第一个输入的零点F,
‫弹出窗口告诉我第一个输入是音高｡
‫然后对丫的我们就可以利用来进行目标轮换了｡
‫是的, 我知道
‫对于这个角色, 我们可以用零点F.
‫现在, 它所做的是创建一个新的F旋转体, 零表示音高, 零表示角色,
‫以及两个目标旋转返回的旋转体分量｡
‫因此, 这个函数返回的值与我们在这里对这三行所做的结果相同｡
‫因为它更简洁, 更优雅,
‫我想我更愿意使用它, 这样我们就可以用调用F旋转器构造函数返回的F旋转器, 初始化旋转向量了.
‫所以我要把这条线去掉｡
‫现在我们来看看旋转｡
‫在此功能中要做的最后一件事是设置炮塔捣碎的旋转｡
‫现在我们可以为给定的组件设置旋转再使用此功能设置世界旋转, 这属于使用场景组件｡
‫我们之所以使用设置单词旋转而不是添加某种局部旋转偏移量,
‫是因为我们在世界空间中有一个旋转, 两个目标是一个世界空间方向向量｡
‫我们将在世界空间中获取炮塔网格位置, 并减去世界空间中的目的位置｡
‫所以这是一个世界空间方向｡
‫因此看旋转是一个世界空间旋转｡
‫因此, 我们将在炮塔网格上使用设置世界旋转｡
‫所以我们会说炮塔网格, 设置世界旋转, 然后我们会传入旋转｡
‫所以现在我们有了一个功能, 可以在世界上的任何目标, 并转动炮塔网格, 以查看它,
‫但它不会向下旋转网格｡
‫它只会改变它的偏航角, 所以它会以坦克炮塔应该旋转的方式旋转｡
‫因此, 我们现在有了一个旋转转台的功能｡
‫我要挑战你们调用这个函数来设置炮塔的旋转, 在坦克类中调用旋转炮塔函数.
‫这是一个受保护的函数｡
‫所以坦克类可以访问它｡
‫现在旋转炮塔取一个F矢量, 看看目标, 你要用我们的线轨迹得到的F命中结果中的那个弹着点｡
‫所以我打算让你自己在代码中找到调用这个函数的正确位置｡
‫所以暂停视频和放置旋转炮塔功能｡
‫叫坦克班来｡
‫好吧, 我会的
‫现在我们有了旋转炮塔功能, 我们可以调用它了｡
‫我将进入tank up, 这是if检查中的tick函数, 用于控制器引用｡
‫我有我的命中结果, 在调用了游标下的get hit result之后, 命中结果将有有效的数据｡
‫实际上, 我们使用的是命中结果影响点并绘制调试球体｡
‫现在, 由于我不再需要绘制调试球体, 我将继续并删除它｡
‫我将把我们保护函数称为旋转炮塔
‫为了查看目标, 我将传入命中结果点弹着点｡
‫所以现在每一帧我们都要把炮塔旋转到命中结果中的撞击点｡
‫在编译之前, 我不再使用draw debug helper, 所以我将删除该头文件｡
‫好吧, 我会的
‫现在我准备编译｡
‫好吧, 我会的
‫我回到编辑室了｡
‫让我们点击播放来看看｡
‫这是惊人的｡
‫我还能滚来滚去｡
‫我可以移动我的鼠标, 无论我移动鼠标光标, 炮塔都在旋转｡
‫所以这是真棒｡
‫好的, 在我们结束之前, 我想先解决几个问题｡
‫我希望这是漂亮的和抛光, 看起来很棒｡
‫现在, 当我将鼠标光标移动到靠近水箱中心的位置, 然后穿过水箱时, 会出现第一个问题｡
‫你会看到在某个点上旋转的速度非常快｡
‫如果我们随意地移动鼠标, 那看起来就不太好了｡
‫断了｡
‫我们没有平稳的移动｡
‫所以这是一个问题｡
‫另一个问题是, 如果我点击鼠标, 然后滚动到边缘, 当我向上移动鼠标光标时,
‫我会看到炮塔向另一个方向移动.
‫那到底是怎么回事？
‫好吧, 让我们来看看｡
‫我们将返回到VS代码, 我想取回我的调试球体｡
‫回到坦克中, 我将在旋转炮塔之前转到tick函数, 并再次调用draw debug
‫sphere｡
‫现在对于我正在经过的世界, 得到世界为中心, 我正在经过的, 命中结果点,
‫撞击点为半径, 我将使用25个点, F段可以是12, 颜色可以是F, 红色持久线可以是假的,
‫寿命可以是负的｡
‫我们之前做过同样事情
‫所以我要保存此通知｡
‫我没有添加头文件, 因为默认情况下, 调试助手实际上是包含的, 所以从技术上讲,
‫我们不需要它｡
‫我将在编辑器中保存跳转, 进行实时编码启动, 然后按“播放”｡
‫现在我有了调试球体｡
‫让我们到世界的边缘, 我把鼠标光标移到它福尔斯到深渊的地方｡
‫这就是我们的问题所在
‫你看, 当我们的光标移动到那里时, 我们在光标下没有命中结果,
‫因为那里没有任何东西可以让我们从中获得命中结果｡
‫因此, 我们的弹着点没有定义｡
‫所以我们需要的是线路追踪的线索｡
‫现在, 虚幻引擎有很多工具, 我们可以使用｡
‫我现在要做的就是点击这里的下拉菜单, 打开我的位置演员面板, 选择这个显示音量的图标,
‫得到一个阻塞音量｡
‫这是阻塞体积｡
‫我会把一个拖进去｡
‫所以现在我有了这个阻塞体积｡
‫默认情况下, 阻塞卷应该是不可见的｡
‫如果我进入细节面板,
‫向下滚动到碰撞, 我会看到它的碰撞预设是无形的墙, 这似乎表明它应该阻止几乎所有的东西｡
‫它唯一没有阻塞的是可见性通道, 我们的线跟踪恰好是针对可见性通道进行跟踪的｡
‫在我们的世界中, 任何阻挡可见性通道的东西都将被我们的线路跟踪击中｡
‫但这本书不会｡
‫它应该是隐形的｡
‫好吧, 我们可以去碰撞预设, 打开下拉菜单, 并选择定制｡
‫这将允许我们改变它, 这样我就可以将碰撞响应设置为可见性通道｡
‫是个街区｡
‫现在我有了一个不可见体积, 但它被设置为阻挡可见性通道,
‫这意味着像我们这样逆着可见性通道追踪的线迹将击中它｡
‫所以我能做的就是把这个块体积放大｡
‫我把它放在墙外｡
‫事实上, 我可以把它放在墙的边界上, 我会把它放低一点,
‫这样它就和墙重叠了.
‫这样我们就有了一个看不见的屏障, 我将继续在Y方向上放大它｡
‫我把这个又大又好的放在中间, 给予一点填充物.
‫我还要在Z方向上放大它｡
‫现在它很好很大我们的线路追踪应该能找到它｡
‫让我们来验证一下这个理论｡
‫让我们在视口中单击并转到墙上｡
‫果然, 我的线跟踪击中了阻塞体积, 我没有问题,
‫我的炮塔捕捉到一些未定义的位置｡
‫它很可能是朝向世界的原点, 因为撞击点矢量都是零.
‫现在如果我走到这面墙前, 我也会遇到同样的问题｡
‫所以我们需要这些阻塞体积｡
‫都在我们这一层的周围｡
‫这很简单
‫我需要做的就是复制这个阻塞卷｡
‫现在, 我可以从透视视图变更为上正投影视图｡
‫我选择顶部, 用鼠标滚轮滚动, 按住alt键, 复制这面墙,
‫在这里放一面, 然后按E键进入旋转模式｡
‫所以我将保持alt并旋转90度｡
‫这会给予我一个副本, 然后我会按两个u, 启动我的翻译模式, 我会把它移到这边,
‫按住Alt键, 把副本拖到那边.
‫所以现在我们有四面墙｡
‫现在我可以从俯视图回到透视图, 然后按播放键, 现在我可以走到任何一面墙,
‫不管我被覆盖在哪面墙上, 看起来都很棒｡
‫这就解决了我们的一个问题｡
‫但是另一个呢？
‫如果我们移动鼠标靠近我们的坦克, 我们仍然有这种零星的行为｡
‫所以我也想处理这个问题｡
‫现在, 我可以处理这个问题的方法是对旋转进行插值｡
‫因此,
‫我们可以使用插值函数来代替直接设置该旋转值, 该插值函数将以平滑的方式将该旋转移向我们提供的目标｡
‫让我们来看看它是如何工作的｡
‫现在, 我希望这个插值函数在我们的旋转炮塔函数中, 这样我们就可以返回到基本兵,
‫向下旋转炮塔, 而不是设置我们的世界旋转, 让炮塔查看旋转,
‫我们可以将其设置为等于插值函数返回的值｡
‫我将删除, 看看旋转, 我们将调用F数学库中的一个函数, 称为R
‫inter2｡
‫现在, 我们的in two设计用于处理旋转器的插值｡
‫现在, 它的第一个输入参数是一个常量F旋转器引用, 称为current｡
‫这是我们试图改变的事物的当前值｡
‫我们试图改变的是我们的炮塔旋转, 我们可以从我们的炮塔网格｡
‫所以我们会说转塔网格, 我们要使用的函数是获得组件旋转｡
‫所以这很像获取组件位置, 只是它获取了旋转｡
‫现在, 下一个输入是名为Target的F旋转器｡
‫这就是价值｡
‫我们希望这个炮塔网格旋转能够顺利地接近｡
‫这将是我们对旋转的看法｡
‫所以我要说看看旋转｡
‫下一个输入是Delta时间｡
‫所以我们知道德尔塔时间的重要性｡
‫如果我们在移动或旋转物体, 我们希望这种移动与帧速率无关｡
‫因此, 我们可以得到德尔塔时间｡
‫我可以简单地包括游戏静态, 如果你有一个很好的记忆力, 你会记得,
‫包括是命运斜线游戏静态｡
‫我在这里得到了游戏静态数据, 这样我就可以访问静态函数, 得到世界增量秒数,
‫记住这需要一个世界上下文对象｡
‫所以我要把这个传给那个｡
‫最后, 我们需要一个内部速度｡
‫内部速度的值越高, 我们向目标插值的速度就越快｡
‫如果我把它设为一个值, 比如说, 5F, 那么我们会很慢地进行插值｡
‫让我们看看现在的情况｡
‫所有这些都在一条线上, 并在屏幕上运行｡
‫所以我要做的就是把设置世界旋转的输入放在它自己的线上, 就像这样｡
‫所以就这样｡
‫然后是我们的解释器, 它有这四个输入参数, 也在屏幕上运行｡
‫所以我要让他们各走各的路｡
‫这样我们就可以看到所有的输入, 而不需要像那样滚动屏幕｡
‫好吧, 我会的
‫我将继续保存它, 并开始实时编码｡
‫现在如果我按下播放键, 移动鼠标, 注意到旋转需要一段时间｡
‫这是因为我们是平滑地向目标旋转插值｡
‫这太棒了
‫这正是我想要的｡
‫不管我怎么移动鼠标, 我永远不会得到那种敏捷的､ 断断续续的移动｡
‫现在, 五是一个非常慢的互联网速度, 但我们可以改变它｡
‫我们可以再快一点｡
‫我将其设置为25, 看看效果如何, 然后让您决定您的游戏所需的值｡
‫所以再一次, 开始实时编码并按播放｡
‫现在我有一个非常快的插值, 但它不是抢购｡
‫它仍然很快, 但它不是一个瞬间的快照｡
‫所以只要我们不做这样的事情, 嗯, 我们就不会得到它｡
‫疯狂的行为｡
‫当然, 如果你想要一个较慢的旋转, 你现在知道怎么做了, 我们已经完成了绘制调试球体,
‫所以我会继续删除它｡
‫好吧, 我会的
‫总之, 我们已经设置了炮塔旋转, 我们正在传递一个目标, 这是一个F向量,
‫对应于世界上的一个点｡
‫现在我们只使用跟踪命中结果｡
‫现在我们把这个函数放在pong基类中, 并使其成为protected,
‫这意味着我们可以继承tank类中的函数｡
‫一旦我们准备好创建一个基于base的塔类, 那么这个塔类将继承这个旋转塔函数,
‫我们可以重用它｡
‫我们只要通过就行了｡
‫在对Target的新看法中, 我们将致力于创建一个从base派生的塔类——在后面的讲座中｡
‫我很快就会见到你的｡