﻿1
00:00:04,480 --> 00:00:05,260
‫Hello and welcome.

2
00:00:05,260 --> 00:00:09,820
‫In this lecture, we're going to be introducing a new thing in the behavior tree, the services.

3
00:00:09,820 --> 00:00:14,560
‫We're going to find out what services are, how they help us with persistent running behavior and how

4
00:00:14,560 --> 00:00:16,390
‫we can write our own in C++.

5
00:00:16,390 --> 00:00:17,380
‫Let's dive right in.

6
00:00:18,060 --> 00:00:23,940
‫Now there are only a few pieces of logic left in our AI controller that aren't in our behavior tree.

7
00:00:24,000 --> 00:00:27,000
‫One of these is setting the start location.

8
00:00:27,000 --> 00:00:30,120
‫This I still want to set here from the I controller.

9
00:00:30,510 --> 00:00:36,210
‫But things like tick now that I would like to do from within our behavior tree.

10
00:00:36,390 --> 00:00:38,100
‫What do I want to do here?

11
00:00:38,190 --> 00:00:40,020
‫How do I get it to do?

12
00:00:40,410 --> 00:00:45,750
‫Set our player location to update the last known player location.

13
00:00:46,200 --> 00:00:51,540
‫Both of these we can do with something called a blueprint service.

14
00:00:51,540 --> 00:00:56,030
‫So let's go over to our blueprints and see what's going on.

15
00:00:56,040 --> 00:01:03,090
‫So if I go to my AI and open up the behavior tree, dock it to the main window, then I need to show

16
00:01:03,090 --> 00:01:03,870
‫you what a service is.

17
00:01:03,870 --> 00:01:10,770
‫We've never used one before, and it's essentially a way of running something every tick or every so

18
00:01:10,770 --> 00:01:14,790
‫often whenever a particular path is active.

19
00:01:14,790 --> 00:01:22,380
‫So if I had a service here on the Chase behavior, then something would some code would be able to run

20
00:01:22,650 --> 00:01:26,880
‫all the time that the Chase behavior is active, whether we're moving, shooting, weighting any of

21
00:01:26,880 --> 00:01:28,800
‫these things, it would always be running.

22
00:01:28,800 --> 00:01:31,200
‫But if we're in investigate it would not be.

23
00:01:31,410 --> 00:01:35,740
‫So this is exactly the kind of situation that we're looking to use a service.

24
00:01:35,760 --> 00:01:38,070
‫Now let's have an example service.

25
00:01:38,070 --> 00:01:44,670
‫One thing that we notice when we're playing is that the once the AI comes within range of us and we

26
00:01:44,670 --> 00:01:51,480
‫move around, he's not rotating to look at us and we can fix that with an already built in service here.

27
00:01:51,480 --> 00:01:58,680
‫So if we right click on this node and go to add service and look for the default focus service, you

28
00:01:58,680 --> 00:02:00,210
‫can see it's a different color, it's green.

29
00:02:00,390 --> 00:02:05,370
‫And if we select that default service, it also goes underneath these sequence nodes as opposed to above

30
00:02:05,370 --> 00:02:06,870
‫them, which is what the decorators do.

31
00:02:07,350 --> 00:02:11,940
‫So with the default focus selected, you can then choose what you want to focus on.

32
00:02:11,940 --> 00:02:17,460
‫And in this case we want to focus on the player location, go ahead and hit save and hit play.

33
00:02:17,460 --> 00:02:23,370
‫And now if we go and have a look and move around, you can see he's rotating to follow us.

34
00:02:23,790 --> 00:02:24,840
‫Cool stuff.

35
00:02:24,930 --> 00:02:32,160
‫Now we want to be able to implement a similar service in C++ that will update our player location all

36
00:02:32,160 --> 00:02:38,940
‫the while and update our last known player location while we are chasing.

37
00:02:38,940 --> 00:02:45,000
‫So we're going to do that as two separate services and you can see how that also automatically services

38
00:02:45,000 --> 00:02:51,090
‫can make things a little bit more efficient than doing it in tick because you can only run the last

39
00:02:51,090 --> 00:02:54,870
‫known player location when you're in the right part of the behavior tree.

40
00:02:54,870 --> 00:03:00,840
‫So let's go over to the sandbox, go to content browser, add new new C++ class, going to show all

41
00:03:00,840 --> 00:03:02,880
‫classes and look for what our options are here.

42
00:03:03,000 --> 00:03:11,370
‫We're looking for BT service and then there are a couple of options just like we had with our BT task,

43
00:03:11,490 --> 00:03:16,080
‫we've got the Blackboard base and we're actually going to want the Blackboard Base because we want to

44
00:03:16,080 --> 00:03:18,180
‫know which key we should be updating.

45
00:03:18,180 --> 00:03:20,640
‫For example, should it be the player location?

46
00:03:20,640 --> 00:03:23,190
‫Should it be the last known player location?

47
00:03:23,310 --> 00:03:28,830
‫So we're going to go and hit next on this one with the Blackboard Base selected and we're going to call

48
00:03:28,830 --> 00:03:36,540
‫this BT service, underscore player location like so and go ahead and create that class.

49
00:03:36,660 --> 00:03:42,870
‫So once we're done compiling, we're going to go over into Visual Studio code and you can see that we

50
00:03:42,870 --> 00:03:48,390
‫have got this BT service player location which is inheriting from the Service Blackboard Base Call.

51
00:03:48,390 --> 00:03:49,110
‫That's what we wanted.

52
00:03:49,110 --> 00:03:51,870
‫Now what functionality we're going to move into this?

53
00:03:52,050 --> 00:03:58,470
‫Well, I'm going to try and move the simplest functionality possible, which is just to set the value

54
00:03:58,740 --> 00:04:01,650
‫of the basically the last known player location.

55
00:04:01,650 --> 00:04:08,340
‫Though this key will be configured in the behavior tree, not here in a plain text, but it's going

56
00:04:08,340 --> 00:04:12,390
‫to get the player -- location and set it to a blackboard key.

57
00:04:12,390 --> 00:04:17,640
‫And it's not going to do any of the line of sight checking reason being if we are running it in our

58
00:04:17,640 --> 00:04:21,930
‫behavior tree only when we are chasing then we don't need the line of sight check.

59
00:04:21,930 --> 00:04:25,470
‫We can see the player that's automatically we know that's the case.

60
00:04:25,470 --> 00:04:29,010
‫So another simplification there for doing it in the service.

61
00:04:29,520 --> 00:04:36,840
‫So this should be fairly straightforward if we know how to get a method call here in the BT service.

62
00:04:37,230 --> 00:04:41,940
‫So let's go and have a look at our BT service to see what is available there.

63
00:04:41,940 --> 00:04:44,100
‫What's the documentation, what can we do?

64
00:04:44,130 --> 00:04:51,120
‫The main methods here you can see are on become relevant on C relevant the tick node and on search start.

65
00:04:51,150 --> 00:04:52,020
‫On search start.

66
00:04:52,020 --> 00:04:54,240
‫We're not particularly interested in but tick node.

67
00:04:54,240 --> 00:05:00,870
‫Yes, that is where we're going to get an update all the time that this service is on an active path.

68
00:05:01,110 --> 00:05:02,970
‫So that's when we're going to want to implement.

69
00:05:02,980 --> 00:05:06,180
‫We go and search through this file to find the full signature here.

70
00:05:06,390 --> 00:05:08,010
‫We can see it is here.

71
00:05:08,010 --> 00:05:09,270
‫Let's see, what section is it in?

72
00:05:09,270 --> 00:05:10,770
‫It's under the protected section.

73
00:05:10,770 --> 00:05:16,890
‫So we're going to go to our BT service that we've created and create a protected section.

74
00:05:17,530 --> 00:05:24,220
‫And paste in, it's automatically an override here because BT Service was inheriting it itself from

75
00:05:24,220 --> 00:05:27,660
‫a parent class, but it's no harm in overriding it again ourselves.

76
00:05:27,670 --> 00:05:32,920
‫We can do a control shift P to create the implementation and then we want to call to super.

77
00:05:32,920 --> 00:05:39,550
‫So we want super tick node and we want to pass in our own comp and our node memory.

78
00:05:39,550 --> 00:05:41,500
‫And let's see, there's some other things in here.

79
00:05:41,500 --> 00:05:46,930
‫We have a Delta seconds as well as what we need to pass up as well and finally finish off with the semicolon

80
00:05:46,990 --> 00:05:49,960
‫should finish off our implementation of tick node.

81
00:05:49,960 --> 00:05:56,320
‫Now in here we basically want to do that behavior from the I controller CP, the one where we are getting

82
00:05:56,320 --> 00:05:59,590
‫the blackboard component, then setting a value as vector.

83
00:05:59,590 --> 00:06:04,120
‫Well, we know how to get blackboard components from owner component references.

84
00:06:04,120 --> 00:06:05,410
‫So that's pretty straightforward.

85
00:06:05,410 --> 00:06:11,590
‫We're just going to do the owner comp dot and then we're going to do the get blackboard component remembering

86
00:06:11,590 --> 00:06:17,980
‫that we need to hash include in here for the behavior tree forward slash blackboard component.

87
00:06:17,980 --> 00:06:20,410
‫Then we can use our arrow operator.

88
00:06:20,500 --> 00:06:27,370
‫And what we should be able to do here is just to set value as vector and then we need a key.

89
00:06:27,370 --> 00:06:30,490
‫Well, we know how to deal with this, but let's just refresh our memory.

90
00:06:30,490 --> 00:06:36,370
‫If we go to our BT service underscore Blackboard Base, you can see same as with the task, we've got

91
00:06:36,370 --> 00:06:38,380
‫the get selected blackboard key.

92
00:06:38,380 --> 00:06:39,310
‫That's what we're going to use.

93
00:06:39,340 --> 00:06:44,950
‫Get selected Blackboard Key gets the key that was selected over in the behavior tree and then we want

94
00:06:44,950 --> 00:06:45,940
‫our vector value.

95
00:06:45,940 --> 00:06:46,840
‫Where are we going to get that?

96
00:06:46,840 --> 00:06:48,580
‫We'll exactly the same as the AI controller.

97
00:06:48,580 --> 00:06:52,960
‫We're going to be getting the player -- first and foremost up here at the top.

98
00:06:52,960 --> 00:06:57,880
‫Then we need to check whether or not this is null and we also need to include our gameplay statics.

99
00:06:57,880 --> 00:07:04,600
‫So let's make sure we have the gameplay statics include from the controller CP included in our player

100
00:07:04,750 --> 00:07:06,130
‫service player location.

101
00:07:06,790 --> 00:07:13,750
‫Then we're going to do and if the player pawn is equal to null pointer, then what we're going to want

102
00:07:13,750 --> 00:07:20,080
‫to do is again return early here it returns void so we can just do a quick early return.

103
00:07:20,140 --> 00:07:29,890
‫Then we can use our player pawn here to simply get the actor location and we may need to do an include

104
00:07:29,890 --> 00:07:30,070
‫here.

105
00:07:30,070 --> 00:07:30,970
‫We'll see how we go.

106
00:07:30,970 --> 00:07:34,420
‫Well, it doesn't hurt to be safe, does it, and explicit about these things.

107
00:07:34,420 --> 00:07:38,890
‫So we're going to do a include for the game framework and then forward slash.

108
00:07:38,890 --> 00:07:44,050
‫It's going to be pawned on H so that we can make sure that we've got everything in order here and then

109
00:07:44,050 --> 00:07:46,090
‫we're just setting the value as vector.

110
00:07:46,090 --> 00:07:47,350
‫That should be all we need.

111
00:07:47,350 --> 00:07:49,210
‫Let's go and compile and see if this works.

112
00:07:49,210 --> 00:07:50,350
‫In fact, one more thing.

113
00:07:50,350 --> 00:07:54,700
‫We probably want a nice pretty name, so we should have a constructor here.

114
00:07:54,700 --> 00:08:00,550
‫So I'm going to create a public section with the constructor, which is going to be the name of the

115
00:08:00,550 --> 00:08:03,760
‫class, and then we go ahead and create that implementation.

116
00:08:03,760 --> 00:08:08,590
‫I'm going to bring my implementation above the implementation for tick node and then we're going to

117
00:08:08,590 --> 00:08:17,020
‫have set the node name equal to it should be update player location and let's build and see if that

118
00:08:17,020 --> 00:08:17,680
‫works.

119
00:08:17,710 --> 00:08:19,300
‫Looks like I had a missing semicolon.

120
00:08:19,300 --> 00:08:20,170
‫Let's try that again.

121
00:08:20,170 --> 00:08:23,350
‫Once that's compiled successfully, we can go over into our enemy.

122
00:08:23,350 --> 00:08:29,350
‫I and as well as the setting focus, want to add a new service which we've got showing up here as the

123
00:08:29,350 --> 00:08:34,600
‫player location which where the pretty name basically comes up as update player location.

124
00:08:34,600 --> 00:08:40,720
‫You can see that it wants to it tells you the frequency of ticking every 0.4 to 0.6 seconds.

125
00:08:40,720 --> 00:08:43,990
‫That's better than using tick because we know tick runs every frame here.

126
00:08:43,990 --> 00:08:46,660
‫This is running less frequently, which is a good thing.

127
00:08:46,660 --> 00:08:52,450
‫And we can go over into the details and create a blackboard key, drop down and select that we want

128
00:08:52,450 --> 00:08:58,720
‫to update is not only the player location but the last known player location, because that will happen

129
00:08:58,720 --> 00:09:02,800
‫every frame as long as we are chasing and that is the behavior that we want.

130
00:09:02,800 --> 00:09:08,940
‫So one more service node we want to go ahead and create is going to do the AI controller's behavior

131
00:09:08,950 --> 00:09:11,230
‫for going down into to tick and see what's left.

132
00:09:11,230 --> 00:09:17,530
‫For us to do here is to update the player location conditional on whether we have line of sight.

133
00:09:17,530 --> 00:09:19,390
‫So we want it to update the player location.

134
00:09:19,390 --> 00:09:22,450
‫If we have line of sight, clear the location if we don't.

135
00:09:22,450 --> 00:09:25,750
‫So that's going to be a new service node because it's a slightly different behavior.

136
00:09:25,780 --> 00:09:28,270
‫We're going to add new new C++ class.

137
00:09:28,270 --> 00:09:33,220
‫We're going to go to show all classes and again, we're going to do BT service, underscore blackboard

138
00:09:33,220 --> 00:09:39,910
‫bases, our base class, and we're going to call it Beat Service Underscore.

139
00:09:40,590 --> 00:09:44,010
‫Player location if seen.

140
00:09:44,130 --> 00:09:46,980
‫And go ahead and create that class.

141
00:09:46,980 --> 00:09:51,120
‫And because this is all stuff you've mostly seen before, it's going to be your challenge to implement

142
00:09:51,120 --> 00:09:51,930
‫this service.

143
00:09:51,930 --> 00:09:57,570
‫So you're going to implement tic node using the code over in the AI controller.

144
00:09:57,570 --> 00:10:04,350
‫As your guide, you're going to need to get hold of the AI controller pointer from within the BT service.

145
00:10:04,350 --> 00:10:09,810
‫Now this is exactly the same as we did in the BT task, so use that as a guidance for getting hold of

146
00:10:09,810 --> 00:10:11,340
‫that AI controller pointer.

147
00:10:11,520 --> 00:10:15,270
‫You'll need the AI controller pointer in order to check for line of sight.

148
00:10:15,270 --> 00:10:21,630
‫Remember, line of sight is a method on the AI controller and then you need to update or clear the key

149
00:10:21,660 --> 00:10:27,270
‫depending on your line of sight check and then place this node in the behavior tree.

150
00:10:27,270 --> 00:10:32,130
‫Where do you think is going to be the right level of the behavior tree for this service to run?

151
00:10:32,130 --> 00:10:33,660
‫How will think about that?

152
00:10:33,660 --> 00:10:37,110
‫Had a little bit of a chin scratch, pause a video and have a go.

153
00:10:38,070 --> 00:10:38,310
‫Okay.

154
00:10:38,310 --> 00:10:38,870
‫Welcome back.

155
00:10:38,880 --> 00:10:44,670
‫So this has opened up a new beauty service over in Visual Studio code.

156
00:10:44,670 --> 00:10:51,750
‫Now it's pretty much going to be identical in the header, so I'm going to go ahead and copy that over

157
00:10:51,750 --> 00:10:59,340
‫into our newly generated header, the exception being that we need to change the name of the constructor

158
00:10:59,340 --> 00:11:00,300
‫to match.

159
00:11:00,300 --> 00:11:07,650
‫Now we're going to create an implementation for the constructor and give it a node name to update player

160
00:11:08,010 --> 00:11:12,690
‫location if seen and add a semicolon on the end here.

161
00:11:12,720 --> 00:11:14,400
‫Let's not forget that this time.

162
00:11:14,400 --> 00:11:21,660
‫Then back into the C++ going to implement tick node as well and I'm just going to copy across if we

163
00:11:21,660 --> 00:11:25,080
‫can find ourselves the player location.

164
00:11:25,080 --> 00:11:31,740
‫CP And just going to copy across the call to super and the getting of the player pawn and the checking

165
00:11:31,740 --> 00:11:32,610
‫of the null return.

166
00:11:32,610 --> 00:11:36,090
‫In fact, I'm going to copy the whole body and we're going to modify it from there.

167
00:11:36,600 --> 00:11:43,380
‫So copying that across and also we're going to be copying the access to the blackboard component with

168
00:11:43,740 --> 00:11:49,290
‫the include for the blackboard component, the gameplay statics and the pawn, because we need access

169
00:11:49,290 --> 00:11:50,160
‫to all of those.

170
00:11:50,160 --> 00:11:53,130
‫In fact, much of the functionality is shared here.

171
00:11:53,130 --> 00:11:58,860
‫You could think about having them somehow share this code, but I think there's not so much duplication

172
00:11:58,860 --> 00:12:00,360
‫that we care enough.

173
00:12:00,840 --> 00:12:05,430
‫So what we going to have to do here is also check that we have an eye controller.

174
00:12:05,430 --> 00:12:15,450
‫So I'm going to do an if the owner component or owner comp dot get I owner is equal to null pointer,

175
00:12:15,720 --> 00:12:19,470
‫then we're going to want to go ahead and return at this stage.

176
00:12:19,950 --> 00:12:24,360
‫Then the next thing we're going to want to do is check our visibility.

177
00:12:24,360 --> 00:12:32,070
‫So we're going to do an if owner comp dot get I owner and then we're going to do an arrow here and we

178
00:12:32,070 --> 00:12:34,440
‫need to include our controller here.

179
00:12:34,440 --> 00:12:36,900
‫So it's going to be hash include.

180
00:12:38,120 --> 00:12:41,810
‫And then it's going to be I controller H.

181
00:12:42,380 --> 00:12:48,470
‫Then we want to do line and let's see what's the correct usage here.

182
00:12:48,470 --> 00:12:54,650
‫If we go over to the I controller CP, it's line of sight two is what we want.

183
00:12:54,650 --> 00:13:00,380
‫So line of sight two then we need to do line of sight to the player pawn.

184
00:13:00,380 --> 00:13:02,870
‫In this case, do we have line of sight to the player pawn?

185
00:13:03,320 --> 00:13:04,820
‫Is that what we're doing over in the CP?

186
00:13:04,820 --> 00:13:05,810
‫Let's just double check that.

187
00:13:05,810 --> 00:13:06,680
‫Yes, we are.

188
00:13:07,220 --> 00:13:11,450
‫Then we're going to want to go ahead and set the values differently.

189
00:13:11,510 --> 00:13:15,800
‫So we're setting the vector value to the player pawn get actor location.

190
00:13:15,800 --> 00:13:18,620
‫Yes, that's if we've got line of sight else.

191
00:13:18,620 --> 00:13:22,430
‫If we do not have line of sight, we know that we need to be clearing that value.

192
00:13:22,430 --> 00:13:26,030
‫So we're going to be still getting the owner component, get blackboard component.

193
00:13:26,060 --> 00:13:31,640
‫Then it's going to be clear value and we're going to be clearing the value of the selected blackboard

194
00:13:31,640 --> 00:13:37,790
‫key still, and that should pretty much cover us for the implementation of player location.

195
00:13:37,790 --> 00:13:41,480
‫If seen, let's go and compile and see if it works well.

196
00:13:41,480 --> 00:13:42,710
‫The compilation succeeded.

197
00:13:42,710 --> 00:13:44,570
‫Let's go in to the behavior tree.

198
00:13:44,570 --> 00:13:50,420
‫Now the level I want this to run at is basically at the top level in the initial selector, because

199
00:13:50,420 --> 00:13:56,060
‫I want it to be updating the player location basically all the time because we need to be able to abort

200
00:13:56,060 --> 00:13:59,600
‫any of these other behaviors based on the player location being set.

201
00:13:59,600 --> 00:14:02,810
‫So we need to be able to set an unset it at any time.

202
00:14:02,900 --> 00:14:08,240
‫So I'm going to go and right click on the top level selector, add service, add the play location if

203
00:14:08,240 --> 00:14:08,870
‫seen.

204
00:14:09,200 --> 00:14:13,760
‫And then we're going to need to select that service node and select its blackboard key, which is going

205
00:14:13,760 --> 00:14:15,260
‫to be our player location.

206
00:14:15,710 --> 00:14:20,270
‫So that one set in the player location, the update player location, the more dumb one is updating

207
00:14:20,270 --> 00:14:22,220
‫the last known player location.

208
00:14:22,550 --> 00:14:29,270
‫And we should now be able to go down to our AI controller and essentially remove all of this code in

209
00:14:29,270 --> 00:14:33,740
‫TTIC because it's been superseded by our services instead.

210
00:14:33,740 --> 00:14:36,350
‫And we can go ahead and compile and see if that works.

211
00:14:36,350 --> 00:14:41,060
‫Let's go over to the editor and play and see if we've still got our enemy coming up to us.

212
00:14:41,060 --> 00:14:46,580
‫He's coming running to us, loses sight, then comes back at us, starts shooting.

213
00:14:46,580 --> 00:14:46,850
‫Yep.

214
00:14:46,850 --> 00:14:53,000
‫Basically everything is working as it was doing before, except now it's doing it entirely via services

215
00:14:53,000 --> 00:14:55,730
‫that we wrote for ourselves in C++.

216
00:14:55,760 --> 00:15:01,100
‫Next lecture, we're going to be fixing that pesky bug where the AI continues to shoot and eventually

217
00:15:01,100 --> 00:15:03,290
‫manages to kill itself off.

218
00:15:03,290 --> 00:15:04,160
‫I'll see you there.

