‫你好, 欢迎回来｡
‫现在我们有了运动, 但我们没有旋转顶部, 我们称之为炮塔.
‫所以我们希望能够用鼠标来实现｡
‫现在, 看看这里发生了什么｡
‫当我在世界上移动我的鼠标光标时, 我得到了这个红色的球体｡
‫这是我在3D空间中绘制的调试球体｡
‫现在请注意, 当我靠墙向上移动时, 球体也在墙的表面上移动｡
‫因此, 无论我的鼠标光标移动到哪里, 我都会感到这种恐惧,
‫这种恐惧与我根据光标位置点击的任何对象相对应｡
‫这对我们来说很有用, 这样我们就可以在太空中找到一个位置, 我们可以把炮塔旋转到这个位置｡
‫现在, 为了实现这一点, 我们需要在控制器上使用一些功能, 因此我们必须访问控制器上的这些功能｡
‫在这段视频中, 我们将进行设置,
‫我们还将讨论这将如何涉及一个称为“选角”的概念｡
‫现在, 我们需要控制器的原因是, 控制器上有一些函数,
‫允许我们获得光标下的命中结果｡
‫现在我们来谈谈鼠标光标｡
‫假设这是我们的屏幕, 这是我们的鼠标光标｡
‫并且光标尖端处的点对应于屏幕上的位置｡
‫现在, 如果我们移动光标, 我们的目标是坦克的炮塔部分,
‫网格的顶部将旋转, 使其面向光标的方向.
‫现在, 如果我们移动光标, 控制器上有一个函数,
‫我们可以使用它来获得与光标对应的位置｡
‫如果我们从摄像机向光标方向画一条直线,
‫并击中世界上的某个对象, 我们可以获得该位置, 并使用该位置设置坦克炮塔的旋转｡
‫让我来告诉你我的意思｡
‫现在, 为了获得与光标对应的命中位置, 我们需要使用控制器｡
‫现在, 让我们简短地讨论一下控制器｡
‫假设我们在世界上有了棋子｡
‫兵将有一个控制器｡
‫这是一个与兵相关联的不可见对象｡
‫现在, 对于我们的兵, 我们的控制器将具有A型玩家控制器, 在游戏开始时,
‫控制器将拥有兵｡
‫这就是为什么我们可以从相机的角度看到属于我们的兵坦克｡
‫现在, 我们可以访问此控制器｡
‫我们的tank类继承了一个名为Get Controller的函数｡
‫它继承自类.
‫所以我们要做的就是控制这个控制器, 并将它存储在一个变量中, 这样我们就可以用它来访问函数,
‫从而得到光标下的命中结果｡
‫所以让我们为这个做好准备｡
‫现在我在坦克课上, 我们需要访问控制器的地方是开始播放｡
‫如果我们在构造函数中进行, 那就太早了, 我们可能还没有一个有效的控制器｡
‫所以我们需要在坦克类中使用开始play函数.
‫现在我们在基本pong类中有了它, 到目前为止, 我们还没有在基本pong类中使用开始play｡
‫所以我想把它移到坦克课上｡
‫我将突出显示开始播放, 包括注释和受保护的部分, 然后将其剪切｡
‫然后回到坦克阶段, 我将把它粘贴起来
‫让我们在这里添加这个受保护的部分, 就在私人部分的上面, 里面有开始播放｡
‫现在我们已经从基本兵中移除了开始游戏｡
‫我们不再有它在这里, 但我们也需要删除它从基地池塘cpp｡
‫在这里｡
‫我们可以在这里删除它, 现在我们在罐H中声明了它, 但我们还需要在罐CPP中定义它｡
‫因此, 我将在setup player input组件下定义该函数｡
‫所以在没有输入参数的情况下, 它将是无效的｡
‫这是函数体, 我们还需要一个tank来预固定函数名｡
‫现在我们知道, 在玩超级大牌时跟注非常重要｡
‫这样, 开始play函数中的任何功能和任何父类仍将被调用｡
‫现在我们开始｡
‫这是我们可以得到我们的控制器, 并将其存储在一个变量中｡
‫让我们回到坦克H, 创建一个变量｡
‫现在这是私有的,
‫我把它放在私有部分的底部, 这是一个播放器控制器指针类型, 我们可以把它叫做播放器控制器引用.
‫这将是我们对播放器控制器的引用｡
‫现在我们讨论的不是C++引用｡
‫这仍然只是一个指针, 但我们将用它来引用播放器控制器.
‫现在我们有了一个类型为a的播放器控制器ref变量, 我们准备好把控制器存储在这个指针里了.
‫让我们回到Tank Dot CP, 开始游戏, 尝试这样做.
‫是这样｡
‫我要做的就是说player, controller, ref等于然后我会尝试调用get controller.
‫现在得到控制器, 就像我提到的, 在类上｡
‫让我们右键单击并转到定义, 注意这个函数返回一个A控制器｡
‫现在我们的变量是类型A的播放器控制器, 而不是控制器｡
‫所以我们在这里要做的是从get controller中获取返回值, 它是一个控制器指针类型,
‫我们要把它存储在一个A播放器的控制器指针中.
‫请注意, 我们在这里看到了红色的曲线｡
‫它表示类型的值｡
‫无法将控制器指标指派给型别的实体｡
‫播放器控制器｡
‫出现错误｡
‫让我们看一下控制器的文档｡
‫你看看
‫这是控制器｡
‫上面写着继承, 等级制度｡
‫在控制器下面, 我们可以看到一个控制器和一个播放器控制器｡
‫这意味着播放器控制器是控制器的子类｡
‫现在, 在C++中, 我们不能有类型的指针｡
‫播放器控制器存储A控制器的地址值｡
‫控制器是父类型｡
‫播放器控制器是子类型｡
‫您无法取得父型别的物件, 并将它储存在子型别的指标中｡
‫那我们怎么解决这个问题
‫这就是我们的问题｡
‫函数get controller返回A控制器的地址｡
‫我们可以把它存储在A控制器指针里, 但不能存储在A播放器指针里.
‫有趣的是, get controller返回的对象实际上是一个播放器控制器｡
‫所以我们有一个A控制器指针形式的地址, 我们知道它存储了一个播放器控制器,
‫但是如果我们有一个A控制器形式的地址, 我们就不能访问我们需要的函数, 因为它存在于一个播放器控制器上｡
‫调用该函数获取光标下的命中结果｡
‫现在, 如果我们有一个类型为A的控制器指针的值, 并且我们试图获取存在于播放器控制器上的函数,
‫我们将失败｡
‫我们将得到一个编译错误｡
‫既然我们知道对象本身是一个播放器控制器, 它就存储在一个A控制器指针中.
‫我们如何解决这个问题？
‫答案是我们必须铸造｡
‫我们知道控制器是父类, 播放器控制器是子类｡
‫我们知道A控制器不能存储在A玩家控制器指针中｡
‫我们知道我们可以反其道而行之, 有一个A控制器指针存储, 一个播放器控制器的对象｡
‫这就是我们调用get控制器时看到的, 它返回一个A控制器指针, 指向一个A播放器控制器.
‫因此, 如果我们有一个类型为A的控制器指针的值, 我们可以使用一个名为cast的特殊函数,
‫将该指针的类型转换为A播放器控制器指针｡
‫因此, 只要对象本身是我们试图转换到的类型, 转换就会将一个指针的类型更改为另一个指针类型｡
‫现在, 如果我们试图强制转换为一个无效类型, 例如, 我们有一个A控制器指针指向一个播放器控制器对象｡
‫如果我们试图强制转换为一个字符, 则cast函数返回null, 我们说我们的强制转换失败｡
‫所以cast函数看起来像这样｡
‫它是一个模板, 就像创建默认子对象一样｡
‫这个模板函数将适应所选择的类型, 在这个函数中, 我们传入的类型也是我们正在转换的类型｡
‫因此我们传递该类型｡
‫我们想在尖括号内转换两个, 然后把要转换的指针传递到括号内.
‫这里有一个例子｡
‫假设我们要强制转换为播放器控制器和类型为A的控制器类型的指针｡
‫我们将指针传递到括号中, 并在尖括号中传递要转换到的类型｡
‫返回的是a类型的播放器控制器指针的值｡
‫这是函数调用, 我们在尖括号中传递类型,
‫从get控制器返回的控制器指针值可以放在括号中.
‫所以我们需要转换从get控制器返回的值｡
‫这将是你的挑战｡
‫因此在BeginPlay中, 使用controller函数并将该值传递给cast函数, 然后将其转换为播放器控制器｡
‫然后你可以把结果存储在我们的播放器控制器ref指针中, 它是A类型的播放器控制器指针｡
‫暂停视频并执行演员阵容｡
‫好吧, 我会的
‫所以我们几乎已经完成了所有的工作, 我们只需要铸造｡
‫我们要做的就是调用cast函数, 它有尖括号和圆括号｡
‫括号里的是我们要转换的值｡
‫现在get controller返回一个A型控制器的指针｡
‫我把它移到括号里｡
‫我们要转换的类型是播放器控制器｡
‫所以我们再次使用get comptroller返回的值｡
‫这将返回一个审计员指针或地址｡
‫然后我们使用cast将其转换为A播放器控制器｡
‫我们知道, 门控制器返回的对象是存储在A控制器指针中的A播放器控制器对象｡
‫所以在我们转换之后, 返回的是一个a类型的指针, 玩家控制器｡
‫所以我们把它存储在播放器控制器ref中｡
‫既然我们已经以A播放器控制器指针的形式访问了控制器, 我们就可以访问所需的函数,
‫以获取光标下的跟踪命中结果｡
‫因此, 总而言之, 我们使用get controller来获得对控制器的访问权限｡
‫我们还使用cast函数将类型A的控制器指针转换为类型A的播放器控制器指针｡
‫现在我们可以访问所需的函数, 即在A播放器控制器类上的光标下获取命中结果｡
‫因此, 我们将在下一个视频中开始使用此函数｡
‫我很快就会见到你的｡