‫你好, 欢迎回来｡
‫现在我们正在向前和向后移动我们的坦克, 但我们没有办法实际驾驶坦克｡
‫所以在这段视频中, 我们将使用一种叫做局部旋转的方法来实际转动水箱｡
‫这是添加演员局部偏移的旋转模拟｡
‫现在, add actor local offset有多个输入参数, 我们只传入了第一个参数,
‫因为其他三个参数是可选的｡
‫但另外三个中有一个是和扫地有关的｡
‫在我们继续实施轮换之前, 我们将讨论一些关于清扫的内容｡
‫因此, 我回到了ADD Actor Local Offset的文档中｡
‫让我们再看一遍这些输入参数｡
‫第二个叫做B扫描, 它是一个布尔值.
‫现在, 如果我们再向下滚动一点,
‫读取B扫描的信息, 它会显示我们是否扫描到目标位置, 触发沿着重叠, 如果被什么东西挡住, 则在未到达目标位置时停止｡
‫它还继续说明, 仅扫描根组件并检查阻塞冲突｡
‫子元件移动时不扫掠｡
‫如果碰撞处于禁用状态, 则此选项无效｡
‫让我们来讨论一下这在游戏编程中的意义, 扫描是一种由引擎完成的技术, 只要启用了扫描｡
‫如果我们有一个移动对象（如由该圆表示的球体）, 则在该球体移动的每一帧中, 引擎都将执行扫描检查｡
‫这意味着它正在检查该特定帧的移动是否会导致两个对象之间的重叠｡
‫所以我用这个矩形来表示这个方块｡
‫现在让我们考虑一下这是世界上仅有的两个物体｡
‫因此, 当球体移向对象时启用扫描时, 引擎会检查这两个对象是否重叠｡
‫现在, 当球体继续移动时, 假设在其中一帧中,
‫球体移动到与另一个对象重叠｡
‫现在, 启用扫描的功能是引擎将检测此重叠, 并将该球体移回该特定帧,
‫以便它永远不会实际穿透对象｡
‫现在我们实际上看不到球体穿透物体｡
‫引擎会在实际执行移动之前捕获重叠｡
‫所以结果是我们看到球体在没有重叠的地方停了下来｡
‫因此, 如果这个矩形是一面墙, 例如, 球体将停止在墙的表面｡
‫这就是清扫为我们所实现的｡
‫现在, 文档说明如果碰撞处于禁用状态, 则此操作没有任何效果｡
‫因此, 必须启用碰撞才能使扫描工作｡
‫回到坦克CP的move函数, 这里是添加演员局部偏移的调用,
‫如果需要, 我们可以在这里传入另一个输入参数, 第二个是扫描布尔值, 所以我们可以在这里传入true｡
‫让我们编译一下, 看看启用扫描的效果｡
‫现在如果我们按下播放键, 我们试图穿过一堵墙, 我们会看到我们穿过了墙.
‫所以这里有些不太对劲｡
‫现在, 让我们了解一下BP水池的路由组件是什么｡
‫回想一下, 我们在路径中使用了胶囊组件｡
‫所以用胶囊组件选定在BP池罐内｡
‫让我们转到详细信息面板并向下滚动, 我们将在这里看到一个名为“碰撞”的部分｡
‫这里我们可以看到“碰撞预设”, 它有一个下拉菜单｡
‫让我们把它扩展一下｡
‫现在, “碰撞预设”可以设置为任意数量的选项, 默认情况下, 我们会看到所有动态重叠｡
‫现在, 根据你使用的虚幻引擎的版本｡
‫您可能会在此处看到其他内容, 但我们可以更改此内容｡
‫如果我们选择下拉菜单并选择“阻止所有动态”, 则下面的灰显选项会发生变化｡
‫请记住, 我们是在重叠所有动态, 这里我们看到三列复选框｡
‫这些是碰撞响应, 左侧的列显示碰撞对象类型的列表｡
‫因此, 任何给定的组件都有其自己的碰撞对象类型｡
‫请注意, 我们可以看到胶囊的对象类型设置为世界动力学｡
‫当我们更改碰撞预设以阻止所有动态时, 您会看到碰撞响应都被选中以阻止所有其他碰撞对象类型｡
‫让我们按下播放键, 看看当我们试图穿过物体时会发生什么｡
‫您会看到我们在与重叠的地方停止｡
‫其他池塘｡
‫现在, 如果我移动水池这样我们就可以尝试与墙重叠然后绕过其他池塘.
‫现在, 如果我按下播放, 我也会挡住墙｡
‫因此, 此碰撞预设块, 所有动态设置碰撞响应以阻止所有其他对象类型｡
‫您可以随时查看特定组件的碰撞对象类型,
‫方法是在组件面板中选择该组件, 向下滚动到详细信息面板中的碰撞部分, 然后打开“碰撞预设”下拉列表｡
‫我选择了基础网格, 其对象类型为世界动态, 并设置为全部阻止｡
‫现在我们可以看到, 由于我们为胶囊补偿设置了碰撞预设, 以阻止所有动态, 因此扫描工作正常｡
‫我们在文档中看到, 只有根组件被扫描并检查阻塞冲突｡
‫因此, 其他组件设置为什么并不重要｡
‫我们只是检查根组件是否阻塞了某些内容｡
‫现在, 一个问题, 绊倒了一些学生是, 他们不能移动, 只要他们设置胶囊,
‫以阻止所有的动态｡
‫其中一个原因可能是您的胶囊与地板重叠｡
‫如果胶囊与地板重叠,
‫您将无法移动, 因为如果胶囊组件与它设置为阻挡的东西重叠, 引擎将不允许您的坦克移动｡
‫因此, 一个简单的解决办法是确保你的胶囊不会与地板重叠｡
‫现在, 你可以进入你的BP-—油箱, 确保你的胶囊就在轮子的上方｡
‫我将进入正交视图｡
‫然后选择我的基础网格, 然后把它放下来｡
‫所以轮子就在胶囊组件的下面｡
‫现在如果你的网片在地板上胶囊就在网片上方｡
‫你应该可以走动了｡
‫我现在要按播放键, 开始了｡
‫现在我们已经扫除了障碍, 是时候开始实施轮换了｡
‫让我们返回项目设置｡
‫因此, 我们进入编辑项目设置, 向下滚动到输入, 在输入部分, 我们有我们的轴映射｡
‫现在我们已经解决了｡
‫往前走｡
‫现在是时候处理下一个称为Turn的问题了, Turn有D和A, 其中D的比例为1,
‫A的比例为负1｡
‫我们想用D和AX来旋转坦克｡
‫因此, 为了将函数绑定到旋转轴映射, 我们需要绑定一个函数｡
‫现在我们回到V的代码中, 我将进入tank文件, 这样我们就可以创建一个函数来绑定到旋转轴映射｡
‫现在我把这个void函数叫做turn和move.
‫它需要一个浮点输入参数, 我们调用这个值.
‫我们已经声明了这个函数, 让我们定义它和tank CP, 我会把它放在move函数下面｡
‫所以我给了它一个函数体, 我需要类名和函数名前面的双冒号｡
‫现在我们有了一个适当的函数｡
‫现在, 这不是我们唯一需要做的事情｡
‫我们需要确保此函数绑定到称为turn的轴映射｡
‫我们在设置播放器输入组件中执行此操作, 就像我们执行向前移动轴映射一样｡
‫我们将使用玩家输入组件, 我们将使用箭头操作符和绑定轴｡
‫现在, 第一个参数将是包含在文本宏中的轴映射名称｡
‫所以我们要说turn, 因为这是轴映射的名称｡
‫接下来是我们要绑定函数的对象｡
‫我们可以传入这个函数, 最后传入我们想要再次绑定的函数｡
‫我们需要操作员的地址, 这将是一个坦克转弯｡
‫所以就这么简单｡
‫我们已经将转弯函数绑定到转弯轴映射｡
‫唯一剩下的事情就是在turn函数中做一些事情｡
‫现在我们已经看到, 我们有添加演员局部偏移, 但有一个旋转模拟这个函数,
‫它被称为添加演员局部旋转｡
‫它的作用是给演员添加一个局部旋转, 正如它的名字所暗示的,
‫你会看到这个函数有两个不同的版本, 一个使用F旋转器, 另一个使用F四边形.
‫我们将使用一个F旋转器的版本｡
‫这叫做三角形旋转｡
‫就像“添加执行元局部偏移”一样, 它也可以采用一个扫描参数和与“添加执行元局部偏移”相同的另外两个输入参数｡
‫最后这三个输入参数是可选的, 就像添加演员局部偏移一样｡
‫所以我们要传入一个F旋转器, 而不是一个F向量｡
‫现在回到turn函数, 如果我们创建一个F旋转器, 我们称之为Delta旋转, 我们会看到,
‫如果我们右键点击F旋转器, 然后转到定义, 我们会转到旋转器,
‫我们会看到三个float类型的公共成员变量.
‫现在就像F矢量F旋转器只有这三个分量而不是X, Y和Z, 我们有俯仰, 偏航和滚动｡
‫现在, 偏航是我们感兴趣的部分｡
‫它表示围绕Z轴的圆括号中的上轴旋转｡
‫这是我们唯一关心的绕Z轴旋转的类型｡
‫这样我们才能控制坦克｡
‫现在, 我想指出的是, F旋转器也有多个构造函数,
‫默认值也是不初始化的, 就像F向量一样｡
‫因此, 我们可以使用一个接受单个浮点数的函数, 所有组件都将被初始化为该浮点数值｡
‫有一个有三个浮点值, 你可以看看其他的｡
‫现在, 我还要指出, 还有一个零点旋转器, 顺便说一下, 这是一个静态零点旋转器｡
‫这就是为什么我们可以回到坦克CP中, 说, equals, F, rotator, zero,
‫rotator, zero, rotator, 是一个静态成员变量, 你可以访问静态成员函数和变量,
‫就像这样, 通过指定作用域解析操作符的类名, 然后引用静态变量或函数的名字｡
‫这就是我们和你在一起的原因｡
‫游戏静态得到世界三角洲秒是一个静态｡
‫函数, 这意味着我们不需要一个实际的游戏静态类的实例来访问该静态函数｡
‫它已经存在了｡
‫零旋转器和零向量也是如此｡
‫所以我将关闭旋转器h, 我们有这个delta旋转, 它被初始化为零旋转器｡
‫现在, 您的音高和角色被置零, 就像F向量的X､ Y和Z被置零一样｡
‫所以我们需要改变你的组件｡
‫就像我在MOV函数中处理delta位置一样, 让我们为delta旋转创建一些伪代码｡
‫当然, 我们希望将你们的值设置为Delta时间的比例值,
‫因为我们希望这种转向与帧速率无关, 但我们还需要某种转向速度, 我们可以称之为转向速率｡
‫一旦我们设置好了, 我们就可以添加局部旋转, 它将根据F旋转器在每一帧旋转演员,
‫ya将按值缩放｡
‫所以如果我们没有按任何键它就会是零, 如果我们按DX和ax它就会有一个值｡
‫所以现在你有个挑战｡
‫这将像添加演员局部偏移一样工作｡
‫唯一的区别是我们现在是轮流演员｡
‫因为我们需要一些旋转速率来旋转演员, 你要创建一个旋转速率变量, 把它变成一个浮点数,
‫然后把它放在速度变量旁边的私有区域｡
‫使用您的属性公开这个变数, 并选择适当的新属性规范｡
‫现在, 在turn函数中, 您将特别设置Delta
‫rotation, 我们关心的是您的组件将值设置为value乘以我们的turn rate变量, 并乘以delta time,
‫然后您准备好调用add actor local rotation,
‫现在将第二个参数传递到该f旋转器中, 继续, 并为B扫描输入传递true, 因为我们确实希望在旋转时进行扫描, 暂停视频,
‫现在执行坦克的旋转｡
‫好吧, 我会的
‫所以这会相当简单｡
‫我们只需要一个转弯速度变量｡
‫现在我将以低于速度的速度进入油箱并产生浮动转弯速率｡
‫现在你可以把它初始化为某个值, 这没问题.
‫如果它与我选择的不同, 我会选择45 F, 看看它是如何工作的｡
‫但我们要把它暴露在蓝图中, 这样我们就可以在开发过程中改变它｡
‫现在, 我希望它可以在任何地方编辑, 我会坚持在同一类别的运动作为速度｡
‫所以我会把这个属性粘贴到这里, 然后右转, 这样就可以把它设置在任何地方了.
‫现在移动类别和坦克CP｡
‫我已经准备好为Delta轮换设置年份了｡
‫我们称之为三角形旋转｡
‫是的, 我知道
‫我们要把它设为, 价值时间, 转弯角速度时间, 时间增量｡
‫当然, 我们可以通过U游戏静态获取Delta时间, 获取世界Delta秒, 作为世界上下文对象｡
‫所以我把它贴在这里｡
‫现在我知道我的伪代码并不完全匹配｡
‫顺序不对｡
‫德尔塔时间在中间｡
‫这并不重要, 因为当三个值相乘时, 可以按任何顺序相乘, 仍然得到相同的结果｡
‫如果你想知道的话, 如果你把这三个值以不同的顺序相乘, 数学结果还是一样的｡
‫所以不用太担心这个｡
‫现在我们有了δ旋转｡
‫剩下要做的就是调用add actor local rotation, 我们将传入Delta rotation,
‫对于第二个输入, 我们将传入true, 以便在旋转时启用扫描｡
‫我们来编译一下｡
‫好了, 我们现在编好了｡
‫您可能会注意到, 在接下来的几个视频中, 这些行中缺少零矢量和零旋转器｡
‫这是因为我一开始就初始化了这些值, 后来意识到这些值应该至少初始化为零｡
‫所以, 如果你们看到这些线, 在初始化时是这样的, 不要担心,
‫保留零向量和零旋转器, 你们会看到我在不久的将来的视频中看到的｡
‫所以别担心
‫如果您没有看到这些初始化参数, 则它们应该在那里｡
‫我们又回到了编辑器｡
‫让我们点击播放, 我将使用D键, 我们旋转, A键将我旋转回来,
‫我们也可以向前和向后移动｡
‫所以现在我们可以旋转和前进, 我们有能力在世界各地移动｡
‫这是一个伟大的里程碑｡
‫现在我移动得很慢, 但这没关系, 因为我可以选择我的坦克, 我可以搜索移动类别,
‫并改变转弯速度到更高的东西, 如90｡
‫现在我们按播放键｡
‫这是相当快一点｡
‫现在, 如果你觉得这还是有点慢｡
‫当然, 您可以调整这些参数｡
‫所以我要再次选择水箱｡
‫400就改成800吧｡
‫为什么不呢？
‫不要说90, 我们说120｡
‫现在, 如果我按播放, 我会快很多｡
‫所以这看起来真的, 真的很好｡
‫所以回头看看剖面图, 我们现在有了一辆可以在世界各地移动的坦克｡
‫第一个要点肯定是勾选的, 我们正在处理WASD运动｡
‫我们还没有处理鼠标输入, 但我们会处理的｡
‫但我们离完成这个游戏又近了一步｡
‫总之, 我们了解了什么是扫描, 以及如何实现扫描, 使我们的对象不会相互穿过｡
‫我们添加了演员局部旋转, 我们这样做实现了一个可以在细节中调整的旋转速率｡
‫编辑器中的面板, 使开发更容易一些｡
‫干得漂亮
‫我们现在把坦克运到世界各地｡
‫下一个视频里见｡