﻿1
00:00:04,170 --> 00:00:04,650
‫嘿, 你好

2
00:00:04,650 --> 00:00:05,610
‫欢迎回来｡

3
00:00:05,640 --> 00:00:11,010
‫现在我们有了抛射体, 我们知道它会产生命中事件, 所以当抛射体真正击中目标时,

4
00:00:11,010 --> 00:00:14,250
‫我们需要做些什么｡

5
00:00:14,280 --> 00:00:19,200
‫现在, 这将涉及到造成损害, 这意味着我们需要一种方法来跟踪健康｡

6
00:00:19,200 --> 00:00:24,840
‫所以我们要创建一个类来处理健康和伤害, 称为健康组件｡

7
00:00:24,930 --> 00:00:32,690
‫这个功能有自己的类的原因是我们可以在不同的类中重用它, 比如坦克和塔｡

8
00:00:32,700 --> 00:00:35,250
‫那么, 让我们来讨论一下健康方面的内容｡

9
00:00:35,640 --> 00:00:38,900
‫现在我们熟悉了usecene组件类｡

10
00:00:38,910 --> 00:00:43,390
‫这个类是从一个叫做actor组件的类派生出来的｡

11
00:00:43,410 --> 00:00:47,220
‫实际上, 这里是使用场景组件的文档｡

12
00:00:47,220 --> 00:00:53,100
‫在继承层次结构中, 您可以看到它的父级是actor组件｡

13
00:00:53,130 --> 00:00:57,330
‫现在, 你扮演的组件比你看到的组件更基本｡

14
00:00:57,420 --> 00:00:59,070
‫它没有变换｡

15
00:00:59,070 --> 00:01:05,020
‫所以位置､ 旋转和缩放并不是你这个演员组件所拥有的｡

16
00:01:05,040 --> 00:01:06,930
‫它不支持附件｡

17
00:01:06,930 --> 00:01:12,660
‫您不能将活动组件附加到静态网格组件或胶囊组件｡

18
00:01:12,660 --> 00:01:15,180
‫这只是属于演员的东西

19
00:01:15,180 --> 00:01:20,910
‫因为没有可视化表示或转换, 所以我们不需要将其附加到任何东西｡

20
00:01:21,000 --> 00:01:31,640
‫将此与使用场景组件进行比较, 使用场景组件实际上具有变换与将自身附加到其他组件或让其他组件将自身附加到其上得能力.

21
00:01:31,650 --> 00:01:36,450
‫因此, 要跟踪健康状况并处理损害, 我们不需要这些东西｡

22
00:01:36,450 --> 00:01:39,990
‫所以你扮演一个组件将是完美的｡

23
00:01:40,170 --> 00:01:44,880
‫因此, 让我们跳回到编辑器, 并使我们的新行为成为一个组件类｡

24
00:01:44,880 --> 00:01:48,690
‫我们将讨论工具和新的C++类｡

25
00:01:48,690 --> 00:01:51,890
‫如果我向下滚动, 我可以看到演员组件｡

26
00:01:51,900 --> 00:01:53,730
‫这就是我们要选择的｡

27
00:01:53,760 --> 00:01:54,630
‫现在小心点

28
00:01:54,630 --> 00:01:56,400
‫不选择演员｡

29
00:01:56,400 --> 00:01:57,750
‫那是另一种课｡

30
00:01:57,750 --> 00:02:02,610
‫它实际上是一个更大的类, 比actor组件包含的内容多得多｡

31
00:02:02,610 --> 00:02:07,560
‫我们特别需要actor组件, 因此请选择它, 然后单击“下一步”｡

32
00:02:07,560 --> 00:02:11,490
‫我们可以简单地称之为健康组件｡

33
00:02:11,880 --> 00:02:13,740
‫让我们单击“创建类”｡

34
00:02:14,190 --> 00:02:21,420
‫现在, 我们有了新的健康组件和CP文件, 您可以在这里看到健康组件,

35
00:02:21,420 --> 00:02:25,980
‫我们刚刚创建的类是从充当组件的组件派生的｡

36
00:02:25,980 --> 00:02:30,390
‫确保这里的类型是正确的, 你会看到它的U｡

37
00:02:30,390 --> 00:02:31,710
‫类宏｡

38
00:02:31,740 --> 00:02:36,360
‫此梅塔指定了蓝图生成表组件的位置｡

39
00:02:36,360 --> 00:02:43,050
‫这样, 我们就可以直接在蓝图中添加此组件, 这也是我们现在要做的｡

40
00:02:43,050 --> 00:02:48,960
‫新的健康组件将关注健康, 这意味着我们需要几个变量｡

41
00:02:48,960 --> 00:02:52,380
‫让我们继续添加这些内容, 并将其设置为私有｡

42
00:02:52,380 --> 00:02:59,700
‫因此, 让我们继续, 在受保护的部分下面添加一个私有部分, 我们可以添加几个健康变量｡

43
00:02:59,700 --> 00:03:04,290
‫这些是彩车, 我把第一个叫做Max Health.

44
00:03:04,320 --> 00:03:12,180
‫这将是我们可以拥有的最大生命值, 我们可以将其设置为默认值, 如100 F｡

45
00:03:12,180 --> 00:03:18,000
‫现在, 除了最大生命值, 我们还有一个生命值, 它是当前的生命值,

46
00:03:18,000 --> 00:03:20,850
‫它会随着我们受到的伤害而变化.

47
00:03:20,850 --> 00:03:24,720
‫让我们再做一个浮点数, 简单地称之为health｡

48
00:03:24,720 --> 00:03:30,900
‫现在我们可以将健康值初始化为零F, 然后设置它的值并开始游戏｡

49
00:03:30,900 --> 00:03:39,690
‫我们这样做的原因是因为Max Health将有自己的you属性, 允许我们从细节面板中设置它｡

50
00:03:39,690 --> 00:03:43,470
‫因此, 让我们给予它一个U属性, 并使它在任何地方编辑｡

51
00:03:43,680 --> 00:03:46,500
‫这样我们就可以在开发过程中改变它｡

52
00:03:46,500 --> 00:03:54,600
‫然后在健康元素CP中, 我们可以简单地将健康值设置为最大健康值.

53
00:03:54,600 --> 00:04:01,860
‫这样一来, 当游戏开始时, 即使我们在详细信息面板中更改了生命值, 生命值仍将为最大生命值｡

54
00:04:02,040 --> 00:04:10,920
‫好的, 让我们编译它, 回到编辑器, 我将打开BP--tank, 然后打开完整的蓝图编辑器｡

55
00:04:10,920 --> 00:04:16,200
‫现在, 我可以在组件面板中添加此运行状况组件｡

56
00:04:16,290 --> 00:04:20,130
‫我将单击“Add and Search for Health（添加并搜索运行状况）”｡

57
00:04:20,370 --> 00:04:22,350
‫这里我们看到了健康｡

58
00:04:22,530 --> 00:04:25,860
‫在C++中我们称之为健康组件｡

59
00:04:25,860 --> 00:04:29,670
‫事实上, 弹出窗口显示它被称为健康组件｡

60
00:04:29,670 --> 00:04:33,420
‫所以在这里显示时, 它去掉了组件部分｡

61
00:04:33,420 --> 00:04:38,220
‫您可能已经注意到, 当您查找静态网格组件或胶囊组件时,

62
00:04:38,220 --> 00:04:40,890
‫您在此处也看不到“组件”一词｡

63
00:04:40,890 --> 00:04:48,270
‫单击“Health”, 现在我们有了“Health”组件, 您会看到在“Health”组件下, 我们有“max Health”,

64
00:04:48,270 --> 00:04:55,080
‫它设置为100, 我们看不到“Health”, 因为我们没有公开该变量｡

65
00:04:55,170 --> 00:05:03,390
‫所以现在BP--tank有一个健康组件, 它说tank拥有这个健康组件, BP--tank｡

66
00:05:03,860 --> 00:05:06,590
‫是此运行状况组件的所有者｡

67
00:05:06,620 --> 00:05:13,760
‫让我们编译并保存, 关闭并打开BP兵炮塔, 打开完整的蓝图编辑器,

68
00:05:13,760 --> 00:05:16,930
‫我们可以添加一个健康组件到池塘炮塔以及｡

69
00:05:16,940 --> 00:05:21,620
‫现在, 我们单击“添加组件”, 搜索运行状况, 然后选择“运行状况”｡

70
00:05:21,620 --> 00:05:25,490
‫现在我们在塔上也有一个健康组件｡

71
00:05:25,670 --> 00:05:30,560
‫所以我将编译并保存这些关闭并保存所有｡

72
00:05:30,590 --> 00:05:38,740
‫我们现在有了一个health组件, 我们提到过我们希望有一个health组件, 这样我们就可以在不同的类中重用它｡

73
00:05:38,750 --> 00:05:44,330
‫所以如果我们有一个兵, 比如说我们的塔, 它会有自己的生命值,

74
00:05:44,330 --> 00:05:47,040
‫那么我们的坦克也会有自己的生命值.

75
00:05:47,060 --> 00:05:52,340
‫现在, 当我们的投射物与其中任何一个相互作用时, 例如,

76
00:05:52,340 --> 00:05:57,680
‫当它产生一个击中事件时, 当击中其中一个时, 那么我们的卒就可以触发健康组件中的一些功能,

77
00:05:57,680 --> 00:06:00,830
‫并改变这些健康值｡

78
00:06:00,830 --> 00:06:07,820
‫将我们的健康功能放在一个组件中, 然后将该组件添加到一个类中, 这比另一种方法有一些优势,

79
00:06:07,820 --> 00:06:13,760
‫例如, 将健康功能简单地放在基本兵类中,

80
00:06:13,760 --> 00:06:17,520
‫然后在坦克和塔中继承它｡

81
00:06:17,540 --> 00:06:26,420
‫你看, 这允许我们保持我们的坦克和塔类小, 只处理这些类的指定功能｡

82
00:06:26,420 --> 00:06:33,800
‫而健康组件可以添加到任何其他参与者, 如不像坦克或塔的东西｡

83
00:06:33,800 --> 00:06:39,950
‫例如, 我们可以制作一面可破坏的墙, 一旦受到足够的破坏, 它就可以被摧毁｡

84
00:06:39,950 --> 00:06:43,910
‫现在让我们来谈谈如何实现这一目标｡

85
00:06:43,910 --> 00:06:50,810
‫虚幻引擎内置了破坏功能, 它的破坏系统实际上相当复杂｡

86
00:06:50,810 --> 00:06:58,490
‫游戏中的任何角色都会继承一些伤害事件, 其中一个是“承受任何伤害”｡

87
00:06:58,490 --> 00:07:03,440
‫这是一个多播委托, 就像组件命中一样｡

88
00:07:03,470 --> 00:07:08,360
‫现在我们将在兵中加入健康元素, 这些元素将基于我们的U｡

89
00:07:08,360 --> 00:07:09,860
‫运行状况组件类｡

90
00:07:09,860 --> 00:07:16,550
‫既然我们知道卒会继承这个on take any damage委托, 那么如果我们在health组件类中创建自己的自定义函数,

91
00:07:16,550 --> 00:07:22,640
‫那么我们可以使用这个函数作为回调函数, 并将其绑定到on take any

92
00:07:22,640 --> 00:07:25,940
‫damage委托｡

93
00:07:25,940 --> 00:07:33,200
‫因此, 无论何时生成一个损坏事件, on take any

94
00:07:33,200 --> 00:07:37,460
‫damage委托都可以广播, 并且在其调用列表中绑定到它的任何函数都将被调用｡

95
00:07:37,460 --> 00:07:42,320
‫那么下一个问题是我们如何让这个代表进行广播？

96
00:07:42,320 --> 00:07:45,080
‫我们需要一种方法来生成损坏事件｡

97
00:07:45,080 --> 00:07:52,070
‫好吧, 在你的游戏静态中有一个功能, 它会做到这一点, 它被称为应用伤害｡

98
00:07:52,070 --> 00:07:58,550
‫如果我们使用游戏静态中的静态函数来应用伤害, 应用伤害需要一些参数,

99
00:07:58,550 --> 00:08:02,180
‫包括受到伤害的演员｡

100
00:08:02,180 --> 00:08:09,620
‫所以如果我们调用apply damage, take上的actors, 任何damage委托都会被触发,

101
00:08:09,620 --> 00:08:11,720
‫并且回调函数会被调用作为响应｡

102
00:08:11,720 --> 00:08:15,830
‫因此, 应用损坏是生成损坏事件的原因｡

103
00:08:15,830 --> 00:08:19,520
‫要设置所有这些, 我们有三个步骤｡

104
00:08:19,520 --> 00:08:25,760
‫首先, 创建一个回调函数,

105
00:08:25,760 --> 00:08:33,950
‫因为它将绑定到任何损坏, 所以它必须具有正确的输入参数, 以便在发生任何损坏时调用它并传递有关损坏事件的所有相关信息｡

106
00:08:34,130 --> 00:08:37,970
‫第二步是将此回调绑定到委托｡

107
00:08:38,000 --> 00:08:43,850
‫我们已经看到了如何使用add动态函数对on组件hit委托执行此操作｡

108
00:08:43,850 --> 00:08:45,530
‫我们在这里也会做同样的事情｡

109
00:08:45,530 --> 00:08:52,670
‫第三步是通过调用you game play的静态函数生成damage事件, 应用damage｡

110
00:08:52,670 --> 00:08:56,210
‫让我们回到代码中, 开始设置｡

111
00:08:56,600 --> 00:08:56,880
‫好吧, 我会的

112
00:08:56,960 --> 00:09:01,910
‫现在我们进入健康组件, 我们将添加一个回调函数｡

113
00:09:01,910 --> 00:09:05,810
‫现在, 这可以是无效的, 我们可以称它为任何我们喜欢的｡

114
00:09:05,960 --> 00:09:08,450
‫我将称之为“已受损害”｡

115
00:09:08,450 --> 00:09:16,280
‫因为我们要将它绑定到一个委托, 所以它必须有适合于该委托的正确输入参数｡

116
00:09:16,310 --> 00:09:23,240
‫现在, 对于绑定到接受任何损坏委托的函数, 输入参数列表必须如下所示｡

117
00:09:23,240 --> 00:09:30,830
‫第一个是一个演员指针, 叫做受损演员, 这就是它的发音.

118
00:09:30,830 --> 00:09:33,320
‫是演员在承受伤害｡

119
00:09:33,350 --> 00:09:38,480
‫接下来是一个叫做伤害的浮动值, 这是实际的伤害值｡

120
00:09:38,510 --> 00:09:45,950
‫现在, 接下来, 我们有一个消耗你的伤害类型指针, 称为伤害类型｡

121
00:09:46,220 --> 00:09:52,430
‫我们之所以有这个输入参数是因为Unreal Engine有损坏类型的概念｡

122
00:09:52,430 --> 00:10:01,100
‫您可以创建具有额外数据的自定义损坏类型, 这些数据可以通知您根据可能存在的损坏类型执行不同的操作｡

123
00:10:01,100 --> 00:10:02,000
‫火的伤害｡

124
00:10:02,000 --> 00:10:03,260
‫毒素伤害｡

125
00:10:03,320 --> 00:10:05,570
‫爆炸伤害等等｡

126
00:10:05,570 --> 00:10:13,430
‫如果你想为每种损坏类型实现自定义功能, 那么你可以在你自己的自定义损坏类型中实现｡

127
00:10:13,460 --> 00:10:19,040
‫现在我们没有创建自己的自定义损坏类型, 但是因为我们将这个函数绑定到接受任何损坏代理,

128
00:10:19,040 --> 00:10:22,940
‫所以它必须有这些输入参数｡

129
00:10:22,940 --> 00:10:24,380
‫所以我们把它包括在这里｡

130
00:10:24,410 --> 00:10:33,330
‫现在下一个参数是A控制器指针, 这被称为煽动者和虚幻的发动机损坏系统｡

131
00:10:33,350 --> 00:10:38,050
‫煽动者是对损害负责的控制者｡

132
00:10:38,060 --> 00:10:46,820
‫所以如果伤害最终是由一个玩家控制一个棋子造成的, 那么煽动者就是控制这个棋子的人｡

133
00:10:46,850 --> 00:10:49,600
‫现在, 并不总是需要一个煽动者｡

134
00:10:49,610 --> 00:10:52,580
‫如果没有, 则这将简单地为空｡

135
00:10:52,580 --> 00:11:00,410
‫现在我得到了红色的曲线, 这样我就可以在函数的括号里向前声明A控制器类了｡

136
00:11:00,440 --> 00:11:06,980
‫现在最后一个参数是A actor指针, 这个参数叫做Damage Causer｡

137
00:11:07,010 --> 00:11:10,370
‫这是造成损害的实际参与者｡

138
00:11:10,370 --> 00:11:13,220
‫这应该是抛射体本身｡

139
00:11:13,310 --> 00:11:20,670
‫所以我们声明了这个damage taken回调函数, 就像我们的其他回调函数一样｡

140
00:11:20,690 --> 00:11:22,970
‫这必须是一个u函数

141
00:11:22,970 --> 00:11:28,550
‫所以我们要给予它一个函数宏, 以确保一旦我们把它绑定到on take any damage委托,

142
00:11:28,550 --> 00:11:30,620
‫它就能工作了｡

143
00:11:30,950 --> 00:11:35,680
‫现在我们已经声明了它, 我们准备在CPP文件中定义它｡

144
00:11:35,690 --> 00:11:38,540
‫在健康成分中, CPP｡

145
00:11:38,630 --> 00:11:46,970
‫在底部, 我将给予它一个函数体, 然后用类名完全限定函数.

146
00:11:46,970 --> 00:11:49,400
‫现在我们有一个回调｡

147
00:11:49,400 --> 00:11:52,400
‫所以现在我们需要将它绑定到委托｡

148
00:11:52,400 --> 00:11:59,180
‫但是委托并不存在于健康组件上, 它特别存在于参与者上｡

149
00:11:59,180 --> 00:12:05,970
‫我们希望将此绑定到拥有此组件的兵中的“接受任何伤害”代理｡

150
00:12:05,990 --> 00:12:11,570
‫那么我们如何访问这个组件的所有者以便绑定到它的一个委托呢？

151
00:12:11,570 --> 00:12:17,270
‫我们可以这样做, 然后开始播放, 我们访问组件所有者的方法是通过git

152
00:12:17,270 --> 00:12:19,460
‫owner函数.

153
00:12:19,460 --> 00:12:23,530
‫如果您将鼠标悬停在上面, 您会看到它返回一个a actor指针｡

154
00:12:23,540 --> 00:12:27,620
‫这是指向拥有组件的参与者的指针｡

155
00:12:27,620 --> 00:12:35,630
‫组件可以由卒拥有, 也可以由参与者拥有, 因此它将以参与者指针的形式返回所有者｡

156
00:12:35,810 --> 00:12:42,890
‫所以我们有了回调函数, 第二步是把它绑定到代理上,

157
00:12:42,890 --> 00:12:46,640
‫以承受拥有健康组件的兵上将要存在的任何损害｡

158
00:12:46,790 --> 00:12:55,100
‫因此, 由于您有将回调绑定到委托的经验, 这将是您在健康组件类中的挑战｡

159
00:12:55,100 --> 00:13:04,190
‫在开始游戏”中, 你将把受到的伤害绑定到该组件所有者的任何伤害代理上｡

160
00:13:04,190 --> 00:13:08,090
‫所以你要通过get owner函数来访问这个委托｡

161
00:13:08,090 --> 00:13:13,640
‫换句话说, 你要调用get owner, 然后从那里你要访问任何损坏｡

162
00:13:13,640 --> 00:13:20,660
‫然后, 您将了解如何使用add dynamic将回调绑定到代理, 如果您遇到问题, 请查看我们如何将on hit回调绑定到on

163
00:13:20,660 --> 00:13:28,250
‫component hit代理, 暂停视频, 并将damage take绑定到on take

164
00:13:28,250 --> 00:13:31,790
‫any damage代理｡

165
00:13:35,000 --> 00:13:35,360
‫好吧, 我会的

166
00:13:35,360 --> 00:13:40,610
‫现在我们回到了健康组件, 我们准备好绑定回调函数了｡

167
00:13:40,610 --> 00:13:47,390
‫从这里开始, 我们将使用git owner函数来访问所有者, 然后我们将使用箭头操作符来访问被调用的委托,

168
00:13:47,390 --> 00:13:54,770
‫take any damage, 在take

169
00:13:54,770 --> 00:14:01,520
‫any damage上有add动态函数, 它只需要一个用户对象和一个函数名.

170
00:14:01,520 --> 00:14:05,240
‫现在, 用户对象就是我们绑定函数的对象｡

171
00:14:05,240 --> 00:14:10,130
‫这个类有回调函数, 就是这样的.

172
00:14:10,190 --> 00:14:14,420
‫最后我们有回调函数, 就是你｡

173
00:14:14,420 --> 00:14:16,790
‫健康组件受损｡

174
00:14:16,790 --> 00:14:23,690
‫现在我们需要记住operator的地址, 因为它实际上取了函数的地址｡

175
00:14:23,690 --> 00:14:31,460
‫所以现在damage taken一定会受到任何伤害, 它会被添加到那个委托的调用列表中｡

176
00:14:31,460 --> 00:14:37,790
‫所以每当我们产生损坏事件时, 我们会从这个代理那里得到一个广播,

177
00:14:37,790 --> 00:14:40,970
‫这将导致损坏接受函数被调用｡

178
00:14:41,570 --> 00:14:50,540
‫总而言之, 我们已经创建了自己的健康组件, 并将其中一个添加到坦克蓝图和塔蓝图中｡

179
00:14:50,660 --> 00:14:58,130
‫我们创建了一个名为Damage Taken的回调函数, 并将其绑定到on take any damage代理｡

180
00:14:58,130 --> 00:15:05,150
‫下一步是生成一个damage事件, 该事件将导致广播on take any

181
00:15:05,150 --> 00:15:10,640
‫damage委托, 以便我们的回调函数damage taked将被调用作为响应｡

182
00:15:10,640 --> 00:15:13,520
‫我们会在下一个视频中设置｡

183
00:15:14,240 --> 00:15:15,140
‫我很快就会见到你的｡

