﻿1
00:00:04,270 --> 00:00:05,200
‫你好, 欢迎｡

2
00:00:05,200 --> 00:00:10,060
‫这节课我们将展示一个松散的屏幕, 我们将完全在C++中进行,

3
00:00:10,060 --> 00:00:13,870
‫以生成这个小部件｡

4
00:00:13,870 --> 00:00:15,490
‫让我们来看看它是如何完成的｡

5
00:00:16,150 --> 00:00:21,640
‫因此, 我们希望在玩家死亡时显示一些UI, 告诉他们发生了什么, 他们已经失去了,

6
00:00:21,640 --> 00:00:23,260
‫级别即将重置｡

7
00:00:23,260 --> 00:00:25,240
‫所以这对他们来说并不奇怪｡

8
00:00:25,240 --> 00:00:31,990
‫所以我们需要创建一些UI, 一个UI小部件, 一个UMG, 虚幻的运动图形小部件｡

9
00:00:32,350 --> 00:00:35,830
‫首先, 让我们创建一个文件夹来存储UI｡

10
00:00:35,830 --> 00:00:41,470
‫我已经知道我们将有两个UI项, 所以我想我会在这里有一个UI文件夹, 然后让我们进入这里,

11
00:00:41,470 --> 00:00:47,800
‫右键单击, 然后开始, 你应该已经这样做了, 但是让我来引导你｡

12
00:00:48,070 --> 00:00:52,600
‫我们将转到用户界面部分, 然后选择微件蓝图, 我们将使用的前缀是WP下划线,

13
00:00:52,600 --> 00:00:57,130
‫然后是lose screen｡

14
00:00:57,430 --> 00:01:03,520
‫现在你可以在C++中为这类东西做一些基类, 但是我们在这一节中不会讨论这个｡

15
00:01:03,520 --> 00:01:07,480
‫通常不需要这样做, 而且在Blueprint中做这些事情要容易得多｡

16
00:01:07,480 --> 00:01:13,000
‫在C++中做这件事没有太大的优势, 除非你的UI会变得非常复杂,

17
00:01:13,000 --> 00:01:15,850
‫你想把一些UI逻辑放到C++中｡

18
00:01:15,850 --> 00:01:20,560
‫如果是那样的话, 情况就不是这样了, 所以我们可以继续使用蓝图｡

19
00:01:20,560 --> 00:01:22,510
‫毕竟, UI是一个视觉化的东西｡

20
00:01:22,510 --> 00:01:29,500
‫现在使用可视化工具将其组合在一起是有意义的, 因为您已经知道如何创建小部件｡

21
00:01:29,500 --> 00:01:32,860
‫然后, 我将向给予提出一个挑战, 让你们设置一个失败屏幕｡

22
00:01:32,860 --> 00:01:37,180
‫我们想添加一些文本来解释玩家已经输了, 我们即将重新开始｡

23
00:01:37,240 --> 00:01:42,040
‫希望将文本放在中心位置, 使其可见, 确保在游戏中可见｡

24
00:01:42,040 --> 00:01:45,610
‫然而, 就像我说的, 解释说会有一个重启即将到来｡

25
00:01:45,730 --> 00:01:50,500
‫在你完成这个挑战之后, 我们将看看如何从C++中派生出这个｡

26
00:01:50,500 --> 00:01:53,020
‫你可能已经在Blueprint中看到了如何做到这一点｡

27
00:01:53,020 --> 00:01:55,690
‫我们将看看如何在C++中实现｡

28
00:01:55,690 --> 00:01:57,070
‫所以暂停视频, 开始吧｡

29
00:01:57,160 --> 00:01:58,420
‫好的欢迎回来｡

30
00:01:58,600 --> 00:02:03,340
‫所以我要去创建, 首先, 一点文本｡

31
00:02:03,340 --> 00:02:09,400
‫所以我想在左边的调色板中查找, 查找文本项并将其引入｡

32
00:02:10,090 --> 00:02:17,270
‫我会把它改成, 你输了, 非常直接, 缺乏想象力的对话, 我们会把颜色,

33
00:02:17,290 --> 00:02:22,900
‫不透明度, 或者外观改成红色, 让它非常清楚的表明他们输了｡

34
00:02:22,900 --> 00:02:28,090
‫把它再擦进去一点, 我会扩大字体, 把尺寸变大｡

35
00:02:28,090 --> 00:02:35,320
‫然后我会把文本周围的框放大, 把文本居中｡

36
00:02:35,320 --> 00:02:38,080
‫下面我们来看看合理性, 我会在文本中间画一条线｡

37
00:02:38,080 --> 00:02:44,890
‫如果我把它展开, 看看有没有其他地方可以在音符中居中对齐, 没有｡

38
00:02:44,890 --> 00:02:55,150
‫我先把盒子的尺寸做得大致合适, 然后再调整对齐和锚点等｡

39
00:02:55,450 --> 00:03:03,370
‫我将选择锚点下拉列表并选择锚定到中间的预设值, 因为这正是我想要做的｡

40
00:03:03,790 --> 00:03:14,530
‫我想将对齐设置为0｡  5和0｡  5, 这基本上意味着我们是对齐到对象的中心而不是左上角｡

41
00:03:14,770 --> 00:03:16,690
‫我要再做一次锚｡

42
00:03:16,690 --> 00:03:16,930
‫好吧, 我会的

43
00:03:16,930 --> 00:03:19,060
‫那不...那不是很有用｡

44
00:03:19,390 --> 00:03:24,520
‫然后是位置X, 如果我把位置设置在0和0附近,

45
00:03:24,520 --> 00:03:31,300
‫因为我已经把锚点设置成这样了, 那么我的亏损位置会在中间的某个地方, 我会把它稍微往上移一点.

46
00:03:31,300 --> 00:03:38,200
‫把我的位置X保持在0, 位置Y-50, 因为我想加入一些辅助文本, 事实上,

47
00:03:38,200 --> 00:03:43,930
‫复制其他文本可能更容易, 因为它已经有了我需要的所有设置｡

48
00:03:43,930 --> 00:03:46,060
‫我只是想把它弄小一点｡

49
00:03:46,060 --> 00:03:55,270
‫再次置零, 我会说, 级别将在5秒后重新启动, 我会使字体大小小很多｡

50
00:03:55,270 --> 00:04:00,460
‫所以它在你脸上的距离会更小, 就像这样,

51
00:04:00,460 --> 00:04:05,950
‫然后把它向下移动一点, 一个小凹口, 不断地把位置X重置为零, 100%满意这个位置｡

52
00:04:05,950 --> 00:04:08,560
‫我只是想把它再往上一点｡

53
00:04:08,560 --> 00:04:14,560
‫如果我按住shift键, 我就可以把它锁定在我移动的轴上这样它就差不多在中心了.

54
00:04:14,590 --> 00:04:15,640
‫好吧, 我很满意｡

55
00:04:15,640 --> 00:04:18,940
‫现在我们需要继续尝试生成这个东西｡

56
00:04:18,970 --> 00:04:19,870
‫我们要怎么做呢？

57
00:04:19,870 --> 00:04:27,520
‫首先, 我们需要知道我们应该生成什么样的小部件类, 我们需要知道从现在开始我们要在哪里做｡

58
00:04:27,520 --> 00:04:31,870
‫正如我已经说过的, 我认为一个很好的地方来做这是从球员控制器本身｡

59
00:04:32,200 --> 00:04:38,030
‫我们需要知道, 在播放器控制器中, 我们要生成什么类, 什么部件类？

60
00:04:38,030 --> 00:04:42,670
‫我知道这是一个蓝图类, 但我们仍然需要它成为一个我们要生成的类.

61
00:04:43,000 --> 00:04:48,880
‫我们要做的就是在这里创建一个新的属性,

62
00:04:48,880 --> 00:04:57,250
‫可以在任何地方编辑, 我们要把它作为的子类, 因为这是确保我们得到一个新类的好方法｡

63
00:04:57,250 --> 00:05:05,350
‫基本上, 如果你愿意, 你可以使用你类的类型, 但这并不限制我们可以使用什么样的类｡

64
00:05:05,350 --> 00:05:09,790
‫在这里, 我们希望将其限制为只能使用小部件｡

65
00:05:09,790 --> 00:05:17,390
‫如果你翻到你的蓝图, 你可以看到如果我们翻到这里的某个地方, 你可以找到那里｡

66
00:05:17,410 --> 00:05:22,930
‫父类是使用一个我们知道的小部件, 当你把前缀放在它上面时, 它就变成了你使用的小部件｡

67
00:05:23,050 --> 00:05:26,680
‫所以这是的子类｡

68
00:05:27,490 --> 00:05:34,360
‫然后我们用尖括号表示一个小部件, 我在这里直接声明这个小部件, 而不是做任何包含,

69
00:05:34,360 --> 00:05:40,150
‫所以我们称之为lose

70
00:05:40,150 --> 00:05:46,630
‫screen类, 这样就能清楚地看到里面发生了什么.

71
00:05:47,020 --> 00:05:56,710
‫现在, 我将继续在这个阶段进行编译, 而我们将进行下一步工作, 因为在更改头文件时进行编译会花费更长的时间｡

72
00:05:56,710 --> 00:06:02,860
‫现在, 实际上编译将在此阶段失败, 因为我们还没有包括UMG模块｡

73
00:06:02,860 --> 00:06:03,820
‫我们不知道该怎么做｡

74
00:06:03,820 --> 00:06:09,760
‫不要担心在这个阶段的编译, 在大约9分钟的视频, 我们将修复这个错误｡

75
00:06:10,060 --> 00:06:14,560
‫现在在C++中, 我们要做的就是生成这个小部件.

76
00:06:14,560 --> 00:06:17,290
‫所以我们想在时间到来之前就开始｡

77
00:06:17,290 --> 00:06:20,320
‫这并不重要, 因为计时器不会等待｡

78
00:06:20,320 --> 00:06:24,820
‫它只是设置时间, 然后直接进入下一行代码, 因此,

79
00:06:24,820 --> 00:06:29,860
‫如果我们直接执行此操作, 如果我们直接生成UI, 我们将不会等待5秒, 我们以什么顺序执行此操作并不重要｡

80
00:06:30,220 --> 00:06:36,520
‫因此, 我们要做的是使用一个名为create widget的函数, 该函数目前还不可用｡

81
00:06:36,520 --> 00:06:38,980
‫所以我们需要先散列包含一些东西｡

82
00:06:38,980 --> 00:06:50,260
‫我们要包含的是蓝图正斜杠用户小部件, 这是我们访问此创建小部件函数所需的类｡

83
00:06:50,740 --> 00:06:53,620
‫基本上, 我们会说创建小部件｡

84
00:06:53,620 --> 00:06:58,270
‫它需要, 嗯, 实际上, 让我们看看我们需要提供它｡

85
00:06:58,270 --> 00:07:00,910
‫我要F 12去实现它｡

86
00:07:00,910 --> 00:07:07,330
‫您可以看到, 这看起来有点复杂, 但我们在这里确实有一个模板参数, 它基本上是默认情况下您使用的小部件,

87
00:07:07,330 --> 00:07:11,080
‫因此我们可能不必提供它｡

88
00:07:11,590 --> 00:07:19,390
‫然后是我们需要创建的所有对象和类, 然后是一个小部件名称（我们不一定需要提供）,

89
00:07:19,390 --> 00:07:23,830
‫然后它作为指向小部件的指针返回｡

90
00:07:24,040 --> 00:07:29,200
‫所以我在这里要做的是, 给予它一个所有者对象.

91
00:07:29,200 --> 00:07:31,560
‫现在, 只有某些对象可以拥有该小部件｡

92
00:07:31,580 --> 00:07:36,310
‫其中一个就是播放器控制器, 我们可以把它传入.

93
00:07:36,310 --> 00:07:40,750
‫接下来我们要在RT子类中传递你使用的一个小部件｡

94
00:07:40,750 --> 00:07:46,540
‫幸运的是, 我们已经在头文件中配置了它, 所以我们可以继续传递它,

95
00:07:46,540 --> 00:07:52,150
‫我将阻止缩进尝试修复自己, 而我还没有在行尾放置分号,

96
00:07:52,150 --> 00:07:55,420
‫然后让我们看看还有什么｡

97
00:07:55,420 --> 00:07:56,050
‫好吧, 就这样了｡

98
00:07:56,050 --> 00:07:58,540
‫此时, 它只返回小部件｡

99
00:07:58,540 --> 00:08:06,910
‫我们可以做的是用一个指针指向你, 使用一个小部件星星, 这将是我们的失败屏幕｡

100
00:08:06,910 --> 00:08:09,310
‫所以我们上了“失去屏幕”的课｡

101
00:08:09,310 --> 00:08:13,000
‫在我们创建了小部件之后, 它就变成了一个实际的松散屏幕｡

102
00:08:13,000 --> 00:08:16,060
‫接下来我们需要做的是使这个UI可见｡

103
00:08:16,060 --> 00:08:20,020
‫我们用虚幻的说法把它添加到视口中来做到这一点｡

104
00:08:20,020 --> 00:08:27,100
‫但首先, 因为我们通过在蓝屏上调用函数来添加到视口, 所以我们需要确保它不是空指针｡

105
00:08:27,100 --> 00:08:32,410
‫那么如果失去屏幕不等于空指针, 为什么它会是空指针呢？

106
00:08:32,410 --> 00:08:37,210
‫顺便说一下, 如果你能弄清楚为什么我们最终会得到一个空指针, 这对你来说是一个挑战｡

107
00:08:37,600 --> 00:08:41,200
‫一个原因可能是我们忘了设置屏幕丢失类｡

108
00:08:41,200 --> 00:08:46,180
‫如果是这种情况, 并且我们没有有效的蓝屏类集, 那么create

109
00:08:46,180 --> 00:08:47,860
‫widget将为我们返回空指针｡

110
00:08:47,860 --> 00:08:54,340
‫我们不希望这种情况发生, 我们也不希望在一个空指针上调用一个函数｡

111
00:08:54,340 --> 00:08:56,500
‫所以我们要做的是丢掉屏幕箭头｡

112
00:08:56,740 --> 00:09:01,270
‫这里我们需要一个名为add to viewport的函数｡

113
00:09:02,060 --> 00:09:07,820
‫这就是简单地要做的, 去把它添加到屏幕上, 这样我们就可以看到松散的屏幕｡

114
00:09:08,090 --> 00:09:14,780
‫现在, 我也将继续编译它, 然后进入一个卷轴,

115
00:09:14,780 --> 00:09:17,330
‫打开播放器控制器的蓝图｡

116
00:09:17,330 --> 00:09:19,100
‫所以这里是射手玩家控制器｡

117
00:09:19,550 --> 00:09:25,520
‫我们应该能在这里的某个地方看到一个还没有出现的变量｡

118
00:09:25,640 --> 00:09:27,110
‫也许我有一些构建错误｡

119
00:09:27,110 --> 00:09:28,850
‫让我们去看看消息日志｡

120
00:09:29,180 --> 00:09:36,140
‫是的, 我们可以在这里看到一些构建错误, 即这些关于外部符号丢失的奇怪错误｡

121
00:09:36,140 --> 00:09:41,780
‫如果我们有一些关于你的东西,

122
00:09:41,780 --> 00:09:50,840
‫使用一个现在不可用的小部件, 如果你回想一下之前的几节课, 我们知道这类错误往往是在我们缺少模块依赖性的时候｡

123
00:09:50,840 --> 00:09:57,770
‫因此, 如果我们打开简单的shooter. build. CSS, 我将关闭终端,

124
00:09:57,770 --> 00:10:04,370
‫以获得更多的空间, 那么您可以看到, 我们需要做的是在这里添加一个新的公共依赖项｡

125
00:10:04,580 --> 00:10:12,140
‫最后, 我们要为UMG添加一个公共依赖项, 也就是一个新的逗号｡

126
00:10:12,140 --> 00:10:20,600
‫然后在引号中, 我们将输入UMG, 这基本上允许我们使用这里的include,

127
00:10:20,600 --> 00:10:24,380
‫即蓝图正斜杠用户小部件｡

128
00:10:24,680 --> 00:10:28,700
‫所有这些内容都在一个独立的模块中, 与所包含的标准内容不同｡

129
00:10:28,700 --> 00:10:32,690
‫所以我们确实需要去告诉Unreal我们想在C++中使用那个模块｡

130
00:10:32,690 --> 00:10:34,640
‫让我们继续构建, 看看它是否有效｡

131
00:10:34,640 --> 00:10:36,410
‫现在看起来很成功｡

132
00:10:36,410 --> 00:10:42,500
‫如果我们进入编辑器, 回到我们的射击游戏控制器, 由于某种原因, 我认为它没有正确地重新加载,

133
00:10:42,500 --> 00:10:46,340
‫所以我不得不在编辑器中点击编译｡

134
00:10:46,340 --> 00:10:48,430
‫我们现在回到射击游戏玩家控制器｡

135
00:10:48,430 --> 00:10:50,630
‫最后可以看到输屏类｡

136
00:10:50,850 --> 00:10:57,830
‫我们可以点击下拉菜单, 然后选择AWP, 在屏幕上加下划线, 编译, 保存,

137
00:10:57,830 --> 00:11:00,140
‫然后让我们去杀了自己｡

138
00:11:00,140 --> 00:11:01,900
‫我们会挨几枪的｡

139
00:11:01,910 --> 00:11:03,380
‫砰, 砰｡

140
00:11:03,380 --> 00:11:04,250
‫就这样｡

141
00:11:04,250 --> 00:11:09,320
‫我们的Lou屏幕已经弹出告诉我们发生了什么事情, 该级别将在5秒后重新启动｡

142
00:11:09,320 --> 00:11:10,220
‫它确实做到了｡

143
00:11:10,220 --> 00:11:11,270
‫确实如此｡

144
00:11:11,270 --> 00:11:22,070
‫所以现在您不仅知道如何创建UMG图形, 还知道如何从C++而不是从Blueprint生成这些图形｡

145
00:11:22,070 --> 00:11:30,680
‫下节课, 我们会对事物有一个不那么悲观的看法看看我们是否能为这个博弈创造一些获胜的条件.

146
00:11:30,680 --> 00:11:31,550
‫我会看到你在那里｡

