1 00:00:23.663 --> 00:00:25.298 Hello, this is Lee Young-Hoon 2 00:00:25.942 --> 00:00:32.106 Today we will create enemy characters and FSM for their AI control 3 00:00:32.493 --> 00:00:35.678 In this chapter, we will create enemy actors 4 00:00:35.906 --> 00:00:39.025 And to control their AI, we will use a finite-state machine 5 00:00:39.223 --> 00:00:42.969 Or FSM, in order to distinguish each state 6 00:00:43.375 --> 00:00:47.731 And we will also learn how to implement action for each state 7 00:00:47.989 --> 00:00:52.416 First, let's create our enemy actors and apply their appearances 8 00:00:52.990 --> 00:00:56.772 Creating Enemy Actor & FSM-Based States 9 00:00:57.495 --> 00:00:59.755 Let's first create our enemy class 10 00:01:01.240 --> 00:01:06.776 Go to Tools, 'New C Class', and let's go with 'Character' 11 00:01:07.360 --> 00:01:10.749 Next, let's call it Enemy 12 00:01:28.383 --> 00:01:32.750 We would need to first add things like appearance or collider 13 00:01:32.750 --> 00:01:35.242 But since Enemy is a character 14 00:01:36.786 --> 00:01:38.023 It should have all of these already 15 00:01:38.023 --> 00:01:42.671 So let's just do some touch-up on our Mesh 16 00:01:43.146 --> 00:01:48.589 Let's go back, and remember what we did for creating our Player 17 00:01:49.916 --> 00:01:50.858 Let's look at our Player 18 00:01:54.199 --> 00:01:59.560 Capsule, Mesh, and Movement Comp, Arrow 19 00:01:59.560 --> 00:02:02.804 These are the four preset components 20 00:02:03.318 --> 00:02:09.649 Here, at Mesh Component there is SKM_Quinn 21 00:02:09.866 --> 00:02:12.000 Let's use the same Quinn 22 00:02:12.000 --> 00:02:13.241 To do that, copy this 23 00:02:14.142 --> 00:02:16.958 You can copy it here as well, so copy 24 00:02:19.037 --> 00:02:21.456 And back to our Class 25 00:02:22.080 --> 00:02:30.686 Here, with this string, we will load it to this address 26 00:02:31.686 --> 00:02:39.111 Now, this will load the Mesh Asset 27 00:02:40.517 --> 00:02:44.226 And apply it to our Mesh 28 00:02:47.987 --> 00:02:50.088 Now let's write this out 29 00:02:50.247 --> 00:02:55.449 To do so, remember how we used ConstructorHelpers? Like so 30 00:02:56.360 --> 00:02:58.354 And let's use FObjectFinder 31 00:02:58.354 --> 00:03:00.624 Make sure to add the angle brackets like so 32 00:03:01.298 --> 00:03:05.346 Let's name it 'TempMesh' 33 00:03:07.287 --> 00:03:09.293 And let's add TEXT 34 00:03:11.144 --> 00:03:14.985 And we can add whatever we have down here 35 00:03:16.925 --> 00:03:20.659 And this will load this part 36 00:03:22.887 --> 00:03:26.260 What goes here is the information that we will be loading 37 00:03:26.517 --> 00:03:30.011 So it will be SkeletalMesh 38 00:03:30.328 --> 00:03:31.456 Make sure to start it with 'U' 39 00:03:34.047 --> 00:03:37.039 Let's check if it has loaded successfully 40 00:03:37.168 --> 00:03:42.787 If TempMesh, Succeeded 41 00:03:46.240 --> 00:03:48.726 Then, GetMesh 42 00:03:50.839 --> 00:03:51.988 It will be applied there 43 00:03:55.857 --> 00:03:59.873 Like so, SkeletalMesh 44 00:04:00.853 --> 00:04:05.198 For TempMesh, add Object 45 00:04:07.307 --> 00:04:12.026 And we will not adjust its location 46 00:04:12.550 --> 00:04:17.263 It is facing rightward, and it is centered at the bottom center 47 00:04:17.580 --> 00:04:21.150 So let's move it downward and rotate it 48 00:04:21.536 --> 00:04:22.897 It's the same procedure here 49 00:04:26.098 --> 00:04:35.242 Bring in our GetMesh, and this function called SetRelativeLocationAndRotation 50 00:04:35.401 --> 00:04:38.519 Let's have the value FVector 51 00:04:39.886 --> 00:04:41.915 And then FRotator 52 00:04:46.103 --> 00:04:47.547 This is 0, 0, 90 53 00:04:49.319 --> 00:04:50.323 -90, excuse me 54 00:04:51.977 --> 00:04:55.117 And for Rotator, see here 55 00:04:56.226 --> 00:04:57.820 The order goes Pitch, Yaw, Roll 56 00:04:57.820 --> 00:05:01.883 Here, Pitch is y, and Yaw is z 57 00:05:02.467 --> 00:05:04.331 So the order is y, z, x 58 00:05:04.331 --> 00:05:09.119 So here we need 0, -90, 0 59 00:05:15.843 --> 00:05:17.940 Let's finish setting it like this 60 00:05:23.959 --> 00:05:27.998 Now let's come back to Unreal, first compile 61 00:05:27.998 --> 00:05:32.453 And let's create our Enemy at Bluepirnt to check 62 00:05:34.483 --> 00:05:35.087 Like so 63 00:05:39.017 --> 00:05:42.978 Right click on Enemy and Create Blueprint 64 00:05:44.235 --> 00:05:47.586 At our folder Blueprint, name it 'BP_Enemy' 65 00:05:50.658 --> 00:05:53.197 Now we have set it like so 66 00:05:54.702 --> 00:05:55.896 Let's first compile 67 00:05:57.678 --> 00:05:59.918 And let's place our Enemy at this Level 68 00:06:00.601 --> 00:06:04.448 Let's rotate Enemy by 180 degrees, so that it faces our Player 69 00:06:09.087 --> 00:06:10.907 Let's place it like so 70 00:06:13.679 --> 00:06:14.670 71 00:06:16.135 --> 00:06:18.936 Like so, we can approach closer 72 00:06:18.936 --> 00:06:21.898 And when we try to shoot, our Enemy does not get hit 73 00:06:21.898 --> 00:06:23.273 The bullet just passes through 74 00:06:23.659 --> 00:06:26.550 Also notice how the the camera acts strangely 75 00:06:26.946 --> 00:06:29.363 When we rotate, it suddenly moves like this 76 00:06:29.818 --> 00:06:30.728 The reason for this is 77 00:06:32.867 --> 00:06:33.480 Here's the concept 78 00:06:33.480 --> 00:06:35.555 Two things; first, it does not get hit because 79 00:06:37.110 --> 00:06:42.313 When we shoot a gun, the Line Trace shoots in a form called Visibility 80 00:06:42.669 --> 00:06:45.268 So this will be that Trace Channel Response 81 00:06:45.268 --> 00:06:47.518 We'll need to take a look at this Trace Response 82 00:06:47.933 --> 00:06:51.748 And then, second, when we rotate the camera 83 00:06:51.748 --> 00:06:53.881 It moves too quickly afterwards 84 00:06:54.168 --> 00:06:58.249 Meaning, when Player is here Player Camera here 85 00:06:58.804 --> 00:07:00.618 Then Enemy is approaching like so 86 00:07:00.618 --> 00:07:02.987 An with the rotation, this camera 87 00:07:05.000 --> 00:07:08.563 The camera moves like so, moving closer 88 00:07:09.445 --> 00:07:11.629 This also has something to do with Trace Channel 89 00:07:11.817 --> 00:07:14.037 And we will be setting two things for our solution 90 00:07:15.512 --> 00:07:18.621 To do so, first double click on Enemy to open it 91 00:07:20.027 --> 00:07:23.630 And at Enemy, at Capsule Component, we have this 'Collision Presets' 92 00:07:24.046 --> 00:07:27.283 And here at Trace Responses 93 00:07:27.481 --> 00:07:29.573 Visibility is at Ignore 94 00:07:29.880 --> 00:07:32.764 And Camera at Block; this is the problem 95 00:07:33.130 --> 00:07:35.413 So let's change these 96 00:07:35.413 --> 00:07:37.835 First, let's make it Custom 97 00:07:38.320 --> 00:07:40.458 For Visibility, Block 98 00:07:40.458 --> 00:07:42.784 And Camera, Ignore; we're reversing the setting 99 00:07:43.655 --> 00:07:45.614 Also because Mesh has its collider 100 00:07:46.040 --> 00:07:49.338 We should set this here as well 101 00:07:49.764 --> 00:07:53.210 Open it, let's go with Custom 102 00:07:54.200 --> 00:07:57.189 And use Ignore for both 103 00:08:00.971 --> 00:08:04.734 In fact, for Mesh, we could just go with NoCollision here 104 00:08:05.556 --> 00:08:10.371 Compile, and let's run it 105 00:08:11.787 --> 00:08:15.101 Now when we shoot, Enemy gets hit 106 00:08:15.101 --> 00:08:18.825 And rotating the camera does not get in the way 107 00:08:19.538 --> 00:08:20.648 So this will be out setup 108 00:08:26.400 --> 00:08:27.793 We will place our Enemy here 109 00:08:27.803 --> 00:08:31.734 And we will add a 'State' for our Enemy 110 00:08:31.734 --> 00:08:33.314 To process it further 111 00:08:34.225 --> 00:08:36.509 Let me first explain the concept 112 00:08:38.143 --> 00:08:40.704 We usually abbreviate it as FSM 113 00:08:40.704 --> 00:08:44.839 The full name is 'Finite State Machine' 114 00:08:50.770 --> 00:08:52.273 That's the spelling of the term 115 00:08:53.937 --> 00:08:56.169 If we add 'In', it will be 'Infinite' 116 00:08:56.278 --> 00:08:59.247 But since it does not have 'In', it is 'Finite' 117 00:08:59.247 --> 00:09:05.111 So it is literally something in a finite state 118 00:09:06.527 --> 00:09:09.740 Or a machine with this state 119 00:09:09.740 --> 00:09:12.271 We sometimes call it a State Machine 120 00:09:12.568 --> 00:09:15.158 Anyhow, the short term for this is FSM 121 00:09:17.684 --> 00:09:20.805 And whenever we work with animations at Unreal 122 00:09:20.805 --> 00:09:22.682 We do it in an 'FSM-based' way 123 00:09:22.969 --> 00:09:25.456 So now, we will be creating an AI 124 00:09:25.456 --> 00:09:27.675 Specifically an FSM-based AI 125 00:09:28.487 --> 00:09:34.249 And when we create this State Machine, we need three things 126 00:09:34.249 --> 00:09:37.638 There things, first is State 127 00:09:39.648 --> 00:09:40.989 We need a State 128 00:09:43.506 --> 00:09:45.661 And we need a Condition 129 00:09:46.898 --> 00:09:48.640 Finally we need a Transition 130 00:09:48.640 --> 00:09:50.115 Transition simply means that something moves over 131 00:09:51.244 --> 00:09:56.844 So we need a Condition, like so 132 00:09:56.844 --> 00:09:58.658 And finally a Transition 133 00:10:01.640 --> 00:10:04.117 It will be helpful to remember these terms 134 00:10:04.344 --> 00:10:07.208 So now let's create this 135 00:10:08.247 --> 00:10:11.108 We will use FSM, in a diagram format 136 00:10:11.375 --> 00:10:17.050 Basically, the Enemy AI can wait 137 00:10:18.159 --> 00:10:21.506 It can move, and it can also attack 138 00:10:23.080 --> 00:10:26.727 And it can also be attacked, getting damage 139 00:10:26.905 --> 00:10:28.611 And finally it can die 140 00:10:29.591 --> 00:10:31.363 These are the five states we will create 141 00:10:31.600 --> 00:10:33.907 To wait, we call this 'Idle' 142 00:10:36.248 --> 00:10:39.429 To 'Move', to 'Attack' 143 00:10:41.400 --> 00:10:42.758 When it gets attacked, let's call it 'Damage' 144 00:10:44.960 --> 00:10:48.372 And it can also 'Die' 145 00:10:49.145 --> 00:10:52.474 We use a rectangular box to visualize the state 146 00:10:52.474 --> 00:10:53.942 So this here is a state 147 00:10:54.239 --> 00:10:55.824 First, it should be 'Idle', right? 148 00:10:56.903 --> 00:10:59.905 And from 'Idle', we can have transition to 'Move' 149 00:11:00.826 --> 00:11:05.647 So from this to 'Move', we have the transition 150 00:11:06.389 --> 00:11:08.293 And this will happen under some condition 151 00:11:08.719 --> 00:11:12.215 When in 'Idle' state, Enemy is looking for Player 152 00:11:12.462 --> 00:11:16.175 So this is the condition; if Enemy finds Player 153 00:11:17.106 --> 00:11:20.705 Then it transitions to 'Move', for example 154 00:11:21.002 --> 00:11:24.939 After 'Move', Enemy will be able to 'Attack' 155 00:11:24.939 --> 00:11:27.020 Because it can only attack after approaching Player 156 00:11:27.020 --> 00:11:29.225 Then it transitions again to 'Attack' 157 00:11:30.829 --> 00:11:34.758 And while at 'Attack' state, it could happen that 158 00:11:34.758 --> 00:11:36.143 Player is not in the attack range 159 00:11:36.638 --> 00:11:37.819 Because, say, Player ran away 160 00:11:38.087 --> 00:11:39.458 Then Enemy should chase Player down 161 00:11:39.458 --> 00:11:42.715 So it can also transition to 'Move' from here 162 00:11:43.388 --> 00:11:46.654 This will be the basic logic behind the movement 163 00:11:46.654 --> 00:11:50.309 And now for 'Damage' or 'Die' 164 00:11:50.626 --> 00:11:53.618 These are both external factors 165 00:11:55.907 --> 00:11:59.283 Here in our example, Player shoots a gun 166 00:11:59.283 --> 00:12:03.514 So with that gun, Player 'Damages' Enemy 167 00:12:03.880 --> 00:12:05.865 Now it's the 'Damage' state 168 00:12:06.865 --> 00:12:08.935 For this, a concept of HP or stamina will help 169 00:12:08.935 --> 00:12:13.440 If there is some HP left, Enemy stays in 'Damage' 170 00:12:13.440 --> 00:12:14.879 And once its HP hits 0 171 00:12:14.879 --> 00:12:17.281 Then we can move to the 'Die' state 172 00:12:17.499 --> 00:12:18.991 That's the basic logic 173 00:12:18.991 --> 00:12:22.277 For example, for 'Any State' 174 00:12:25.479 --> 00:12:30.296 'Damage' and 'Die' are 'Any State' because we can reach there from 'Idle' 175 00:12:30.296 --> 00:12:31.643 Or from 'Move' or 'Attack' 176 00:12:31.643 --> 00:12:34.916 Meaning, the transition can happen from 'Any State' 177 00:12:35.649 --> 00:12:38.087 For example, we can have 'Attack' 178 00:12:43.316 --> 00:12:46.430 And after 'Attack' Enemy can go to 'Die' state 179 00:12:48.915 --> 00:12:50.411 It could just die like that 180 00:12:50.411 --> 00:12:53.711 Let's implement it following this diagram 181 00:12:53.711 --> 00:12:55.802 So let's start with this 182 00:12:55.802 --> 00:13:01.431 This time, we made an Enemy Class for our Enemy 183 00:13:01.679 --> 00:13:04.337 Let's add a component here 184 00:13:06.880 --> 00:13:11.820 Let's add a component called Enemy FSM like so 185 00:13:12.641 --> 00:13:16.362 So when we implement it at this component 186 00:13:16.897 --> 00:13:22.042 Between the main Character class and its FSM 187 00:13:22.824 --> 00:13:26.229 How can these two exchange information? 188 00:13:26.229 --> 00:13:27.845 We will be covering that together 189 00:13:28.707 --> 00:13:32.372 So let's create a component 190 00:13:33.057 --> 00:13:38.712 At Tools, down here we see two types of component 191 00:13:39.009 --> 00:13:41.792 We have Actor and Scene for components 192 00:13:42.782 --> 00:13:45.892 Actor Component is for something that exists 193 00:13:46.289 --> 00:13:48.763 And Scene Component is for something that transforms as well 194 00:13:49.456 --> 00:13:51.436 And we do not need the transform 195 00:13:51.436 --> 00:13:54.934 So let's create a class with this Actor Component 196 00:13:55.756 --> 00:14:02.629 Next, let's name it 'EnemyFSM' 197 00:14:15.589 --> 00:14:18.846 So here's our EnemyFSM, and it's time to create some state 198 00:14:19.459 --> 00:14:25.969 The best way of creating state is using enumerated type 199 00:14:26.305 --> 00:14:28.192 So let's use some enumeration 200 00:14:28.450 --> 00:14:31.864 Unreal provides their own enumerated type 201 00:14:31.864 --> 00:14:35.634 It's called UENUM, and here's the macro for that 202 00:14:36.297 --> 00:14:40.082 Let's use that and write out 'enum class' 203 00:14:41.656 --> 00:14:44.243 For enum, there is a scoped one and unscoped one 204 00:14:45.045 --> 00:14:49.440 So let's create our scope in a class type using enum 205 00:14:50.420 --> 00:14:54.453 Let's name it Enemy State 206 00:14:55.057 --> 00:14:58.674 And if we want to see it at Blueprint as well 207 00:14:59.377 --> 00:15:04.062 Just add 'BlueprintType' 208 00:15:05.022 --> 00:15:11.147 And when we do this, we always use unit8, meaning unsigned 209 00:15:11.147 --> 00:15:13.948 This is the rule when we implement this 210 00:15:14.374 --> 00:15:18.969 And then, for your case, you can just change the name here 211 00:15:18.969 --> 00:15:23.325 And for enumerated type, you add 'E' before the name 212 00:15:23.681 --> 00:15:24.830 So that's what we have 213 00:15:24.979 --> 00:15:33.842 And here, let's add Idle, Move, Attack, Damage and Die 214 00:15:34.129 --> 00:15:35.237 Let's add these five 215 00:15:35.950 --> 00:15:39.664 You can add a comma at the end, or you can skip it 216 00:15:40.307 --> 00:15:42.878 And if you want these to be some different names 217 00:15:42.878 --> 00:15:47.509 At Blueprint, go ahead and use UMETA 218 00:15:47.509 --> 00:15:51.298 This macro will allow changing the display name 219 00:16:03.506 --> 00:16:05.487 This is optional 220 00:16:05.487 --> 00:16:08.647 You can do Ctrl Shift U to capitalize this 221 00:16:09.479 --> 00:16:13.296 With these hotkeys, you can do that 222 00:16:13.474 --> 00:16:15.529 So we're done with that part 223 00:16:16.608 --> 00:16:19.601 And now this is the data type, enumerated type 224 00:16:20.176 --> 00:16:22.446 And let's go down and create some variable 225 00:16:23.159 --> 00:16:26.019 Type 'public' 226 00:16:27.118 --> 00:16:29.267 And let's add 'State' 227 00:16:32.137 --> 00:16:35.763 We will be branching with this State 228 00:16:36.684 --> 00:16:39.758 How do we do that? Come back to this source 229 00:16:41.392 --> 00:16:44.034 And we see 'Tick', here as well for component 230 00:16:44.945 --> 00:16:49.119 So we will start writing here using Switch Statement 231 00:16:49.119 --> 00:16:51.416 Swt, press Tab 232 00:16:51.812 --> 00:16:55.223 And it automatically adds, it has IntelliSense 233 00:16:55.223 --> 00:16:56.633 Or autofill, so here 234 00:16:57.039 --> 00:17:00.192 Write 'State' and press Tab again 235 00:17:00.192 --> 00:17:02.911 And Enter, and we have all these automatically 236 00:17:04.387 --> 00:17:06.129 First, we don't need this default part 237 00:17:06.703 --> 00:17:10.318 Let's start writing, this will be 'Idle' 238 00:17:10.575 --> 00:17:12.760 And for us, since this is Tick 239 00:17:12.760 --> 00:17:17.905 We'll name our variable TickIdle and implement it here 240 00:17:18.895 --> 00:17:22.038 So what's going on here? Tick is when it gets updated 241 00:17:22.038 --> 00:17:25.180 So based on the current state 242 00:17:25.180 --> 00:17:28.244 This will take care of some mechanical control, as in it only does this action 243 00:17:28.877 --> 00:17:33.358 So let's visualize this here 244 00:17:34.299 --> 00:17:35.959 Here's the input 245 00:17:35.959 --> 00:17:39.691 And based on the state 246 00:17:39.691 --> 00:17:41.146 The signal branches 247 00:17:41.760 --> 00:17:45.560 Since we have five, like 'Idle' and so on 248 00:17:45.817 --> 00:17:49.071 And that input, if state is Idle 249 00:17:49.319 --> 00:17:51.298 Then it goes to Idle like so 250 00:17:51.486 --> 00:17:54.794 And if our State value changes to Move 251 00:17:55.160 --> 00:17:59.120 If this is Move, then the input goes to Move 252 00:17:59.863 --> 00:18:02.585 That's what we can do to that signal 253 00:18:03.199 --> 00:18:04.881 And that's what Finite State Machine does 254 00:18:06.842 --> 00:18:09.971 So we can assign a variable for each state 255 00:18:09.971 --> 00:18:11.040 For us to control 256 00:18:11.040 --> 00:18:14.153 We can write it out here, but it will be too long 257 00:18:14.906 --> 00:18:16.138 So let's instead create variables 258 00:18:21.407 --> 00:18:22.995 To control these 259 00:18:38.565 --> 00:18:42.318 Implementing Action For FSM-Based State 260 00:18:42.520 --> 00:18:46.524 Since we have them here, let's implement them 261 00:18:49.396 --> 00:18:53.156 At our header, let's create some declaration 262 00:18:58.091 --> 00:18:59.057 Write it out like so 263 00:19:08.838 --> 00:19:10.034 And we have everything 264 00:19:11.232 --> 00:19:12.557 Now we implement it 265 00:19:18.814 --> 00:19:20.046 Write it out like this 266 00:19:20.749 --> 00:19:23.660 And we can use this to process them 267 00:19:23.759 --> 00:19:27.177 Once you do that, the variables below will be complete 268 00:19:27.642 --> 00:19:29.892 And we just need to implement each 269 00:19:30.239 --> 00:19:36.763 The advantage for FSM is that we can divide them 270 00:19:37.219 --> 00:19:39.833 Into different parts to implement each 271 00:19:40.338 --> 00:19:43.273 And we can, through control flow 272 00:19:43.550 --> 00:19:45.548 The action could change among these 273 00:19:45.548 --> 00:19:48.477 And we can process them by turning them into signals 274 00:19:49.299 --> 00:19:52.987 The downside is that this part may get complex 275 00:19:53.333 --> 00:19:55.051 And we may lose some readability 276 00:19:55.051 --> 00:19:58.418 Meaning, we won't be able to see the flow at once 277 00:19:58.418 --> 00:20:02.042 Which could be the problem, but this is the basic part 278 00:20:02.943 --> 00:20:04.172 Let's control each 279 00:20:04.509 --> 00:20:05.726 Starting with 'Idle' 280 00:20:08.627 --> 00:20:10.370 At 'Idle', what will happen is 281 00:20:11.300 --> 00:20:12.708 Time will pass 282 00:20:16.280 --> 00:20:18.262 For example, a second passes 283 00:20:20.272 --> 00:20:22.520 And Enemy looks for Player 284 00:20:24.817 --> 00:20:27.418 It wants to find Player 285 00:20:28.854 --> 00:20:30.517 And if it does 286 00:20:32.439 --> 00:20:35.778 It wants to transition into Move 287 00:20:37.174 --> 00:20:38.255 That's what this does 288 00:20:38.949 --> 00:20:40.410 Let's just write out everything first 289 00:20:40.657 --> 00:20:44.246 At 'Move', it moves 290 00:20:47.958 --> 00:20:48.847 The destination 291 00:20:53.749 --> 00:20:56.107 It wants to move towards it 292 00:20:59.235 --> 00:21:02.346 And it has to calculate the distance left to the destination 293 00:21:02.346 --> 00:21:05.134 Because it can't keep moving forever 294 00:21:05.134 --> 00:21:06.604 It should stop when it's close enough 295 00:21:07.069 --> 00:21:11.218 So get the distance from the destination 296 00:21:14.560 --> 00:21:19.827 And if Enemy can attack in that range 297 00:21:21.263 --> 00:21:23.671 But this is not something that can be implemented 298 00:21:24.018 --> 00:21:28.238 Let's say, if this is in attack range 299 00:21:31.477 --> 00:21:34.384 Then it wants transition into 'Attack' 300 00:21:35.215 --> 00:21:36.779 That's how we can implement it 301 00:21:38.852 --> 00:21:41.427 So here, it branches into another two things 302 00:21:41.585 --> 00:21:45.808 First is to move, and second is to transition after checking for conditions 303 00:21:45.808 --> 00:21:47.450 That's how it branches 304 00:21:48.093 --> 00:21:48.921 Same thing here 305 00:21:48.921 --> 00:21:54.014 It starts with waiting for that time to pass, for that second to pass 306 00:21:54.014 --> 00:21:57.378 And then it transitions, looking for Player 307 00:22:00.137 --> 00:22:01.418 Let's go with TickAttack now 308 00:22:01.418 --> 00:22:05.434 We'll modify this part a lot later, but basically 309 00:22:06.880 --> 00:22:10.290 Let's just say time passes and it attacks 310 00:22:10.924 --> 00:22:11.897 First, time passes 311 00:22:14.560 --> 00:22:20.144 And when the cooldown time passes 312 00:22:20.450 --> 00:22:24.590 Meaning, if the time passed is bigger than the cooldown time 313 00:22:27.760 --> 00:22:29.808 Let's say that, then 314 00:22:32.954 --> 00:22:34.684 Then it attacks 315 00:22:36.427 --> 00:22:38.734 For Attack, let's print some log 316 00:22:38.734 --> 00:22:39.895 Attack works like so 317 00:22:40.736 --> 00:22:43.758 And we need to now reset the time that has passed 318 00:22:47.827 --> 00:22:49.130 That's one task 319 00:22:49.407 --> 00:22:52.226 And second, at 'Attack', after the attack 320 00:22:52.959 --> 00:22:55.093 It calculates the distance from the destination again 321 00:22:55.865 --> 00:23:00.248 So get the distance 322 00:23:02.280 --> 00:23:11.587 And if that is out of the attack range 323 00:23:12.280 --> 00:23:14.047 No, when it is in the attack range 324 00:23:14.532 --> 00:23:17.427 If we are to reuse this, it will say 325 00:23:20.719 --> 00:23:27.479 Something like, bigger than the attack range 326 00:23:32.537 --> 00:23:34.214 Then it will move 327 00:23:34.392 --> 00:23:38.745 Or it will transition into 'Move' 328 00:23:39.458 --> 00:23:40.782 So first, time passes 329 00:23:40.872 --> 00:23:45.347 And we have things like cooldown time and attack range 330 00:23:45.347 --> 00:23:50.454 Let's first implement these 331 00:23:51.454 --> 00:23:53.485 And here, Enemy needs to find Player 332 00:23:53.485 --> 00:23:55.305 And it should remember that it has found Player 333 00:23:55.998 --> 00:23:57.318 That's how it will 334 00:24:00.160 --> 00:24:01.906 Mark Player as the destination 335 00:24:02.272 --> 00:24:05.969 I wrote 'Player' here but it's actually the destination 336 00:24:06.939 --> 00:24:07.997 So let me correct that 337 00:24:10.897 --> 00:24:14.921 So let's add some related variables at our header 338 00:24:16.307 --> 00:24:17.738 First, UPROPERTY 339 00:24:22.361 --> 00:24:25.759 class ATPlayer 340 00:24:26.719 --> 00:24:28.046 That's our target 341 00:24:30.646 --> 00:24:34.946 And to move, we need its owner 342 00:24:34.946 --> 00:24:39.280 Since this is just a component, it can't move right away 343 00:24:39.280 --> 00:24:41.768 What makes it move is not in this component 344 00:24:43.382 --> 00:24:47.791 It's in the owner's Movement component 345 00:24:47.791 --> 00:24:51.045 So in order for that movement, it should remember its owner 346 00:24:51.758 --> 00:24:54.883 For that, we use UPROPERTY 347 00:24:56.738 --> 00:24:58.723 And the owner of this component is Enemy 348 00:24:59.050 --> 00:25:03.186 So class AEnemy, and 349 00:25:03.809 --> 00:25:05.828 Because it's basically myself, let's say Me 350 00:25:06.095 --> 00:25:08.182 Let's capitalize the first letter 351 00:25:10.488 --> 00:25:14.187 And then we also have time, 'float CurrentTime' 352 00:25:17.858 --> 00:25:21.639 and 'float AttackRange' 353 00:25:23.699 --> 00:25:28.249 For attack range, let's say around 150cm or 1.5m 354 00:25:29.268 --> 00:25:34.136 And it needs to wait for a second in the beginning 355 00:25:35.512 --> 00:25:37.593 So we'll say FindTime for that 356 00:25:40.766 --> 00:25:43.955 This will be a second, and 357 00:25:43.955 --> 00:25:47.267 Things like FindTime is what the game designer may change later 358 00:25:51.687 --> 00:25:54.268 We can do this so that the designer can change later 359 00:25:56.308 --> 00:25:58.070 What else, other than FindTime? 360 00:25:59.000 --> 00:26:04.435 AttackRange too, I guess, is something up to the designer to finalize 361 00:26:05.327 --> 00:26:06.865 So we have FineTime 362 00:26:09.297 --> 00:26:12.177 Did we have our cooldown time? 363 00:26:13.970 --> 00:26:15.258 We have our cooldown time 364 00:26:15.258 --> 00:26:17.566 Let's say something like 'Delay Time' 365 00:26:17.823 --> 00:26:21.277 Here, AttackDelayTime 366 00:26:22.337 --> 00:26:25.277 Let's set it as a second for now 367 00:26:27.580 --> 00:26:31.801 For all information regarding the balance, let's add this property 368 00:26:31.969 --> 00:26:35.199 So that the designer can finalize them later 369 00:26:36.467 --> 00:26:39.373 I didn't write 0 but the default is 0 370 00:26:39.779 --> 00:26:41.679 Now, let's fill these in 371 00:26:41.679 --> 00:26:43.163 Let's do this part at BeginPlay 372 00:26:43.599 --> 00:26:47.978 And this can be done at our Idle state 373 00:26:49.137 --> 00:26:50.447 So let's move over here 374 00:26:52.932 --> 00:26:56.944 At BeginPlay, let's start with Me 375 00:26:57.251 --> 00:27:00.438 Me is for the owner 376 00:27:01.349 --> 00:27:04.942 And we need the owner here 377 00:27:06.160 --> 00:27:11.496 This component is what Enemy owns 378 00:27:11.912 --> 00:27:18.229 So let's cast this and have it here 379 00:27:22.756 --> 00:27:23.386 Like so 380 00:27:26.238 --> 00:27:29.364 Whenever we do this, we always need a header 381 00:27:29.364 --> 00:27:31.075 I will add mine automatically here 382 00:27:32.026 --> 00:27:33.643 Add something like this 383 00:27:34.930 --> 00:27:37.780 This is the basic part 384 00:27:37.780 --> 00:27:40.165 Whenever you use a class anew 385 00:27:40.888 --> 00:27:44.511 You need a header whenever you're implementing one 386 00:27:45.353 --> 00:27:46.415 So that was on casting 387 00:27:47.395 --> 00:27:49.734 That was Me, and now back to Idle 388 00:27:49.734 --> 00:27:51.562 Let's implement this part 389 00:27:51.562 --> 00:27:55.752 So time should pass, and it is CurrentTime 390 00:27:56.198 --> 00:28:01.027 And =GetWorld, GetDeltaSeconds 391 00:28:03.010 --> 00:28:04.412 We could do this 392 00:28:05.214 --> 00:28:08.219 Or we can just use the DeltaTimeSeconds variable 393 00:28:11.239 --> 00:28:13.936 See, like so, we can do that 394 00:28:16.307 --> 00:28:18.998 And then after a second passes 395 00:28:19.533 --> 00:28:21.057 Not a second, FindTime 396 00:28:21.433 --> 00:28:29.760 If it is bigger than FindTime 397 00:28:29.760 --> 00:28:33.939 Meaning, if CurrenTime is bigger than FindTime 398 00:28:34.781 --> 00:28:36.832 Then it looks for the destination 399 00:28:38.188 --> 00:28:41.409 And since this is a cycle, let's initialize with 0 400 00:28:42.320 --> 00:28:43.632 And let's start looking 401 00:28:43.632 --> 00:28:47.780 Here, UGameplayStatics is a convenient tool 402 00:28:47.780 --> 00:28:50.277 At UGameplayStatics 403 00:29:04.487 --> 00:29:08.218 Here, we have GetActorOfClass 404 00:29:08.426 --> 00:29:10.446 We can use this, GetWorld 405 00:29:12.317 --> 00:29:14.462 We can also have it look for Player pawn 406 00:29:14.462 --> 00:29:17.035 Or our Player character, like so 407 00:29:17.718 --> 00:29:22.764 So Player is ATPSPlayer 408 00:29:22.764 --> 00:29:24.763 And we can add UClass 409 00:29:25.040 --> 00:29:29.753 So we can add StaticClass 410 00:29:30.594 --> 00:29:34.426 And also, to use this, we need a header like so 411 00:29:36.958 --> 00:29:39.073 Let's add a header here as well 412 00:29:41.168 --> 00:29:43.597 I've stressed on adding the header a few tiems 413 00:29:43.973 --> 00:29:46.432 And here we have this part now 414 00:29:49.448 --> 00:29:50.817 And that's how it's done 415 00:29:53.880 --> 00:29:57.637 Now we found Player, and we need to add this part 416 00:29:57.637 --> 00:29:59.672 We have our variable, Target 417 00:30:01.128 --> 00:30:04.175 So we can just get Target like so 418 00:30:05.868 --> 00:30:09.946 And for GetActorOfClass, it returns AActor 419 00:30:10.688 --> 00:30:14.575 So we can't do this, we need to use casting 420 00:30:15.853 --> 00:30:17.996 So that's how we do it 421 00:30:25.398 --> 00:30:26.560 And now we have this part 422 00:30:26.560 --> 00:30:28.427 And if Target is not null 423 00:30:30.199 --> 00:30:33.817 Like so, if Target, not null, then State should be 424 00:30:36.698 --> 00:30:40.087 Transitioned to 'Move' state 425 00:30:40.770 --> 00:30:42.425 And 'transition' here means 426 00:30:42.425 --> 00:30:45.279 That we are changing this value here 427 00:30:48.285 --> 00:30:52.505 And for transition, we use time 428 00:30:53.268 --> 00:30:58.142 When it moves, when it gets the distance, and when it attacks, right? 429 00:30:58.142 --> 00:31:00.553 So we will be reusing this CurrentTime 430 00:31:01.959 --> 00:31:05.815 So let's set it as 0 when we use it 431 00:31:05.815 --> 00:31:08.880 But doing this every time will be a bit time-consuming 432 00:31:08.880 --> 00:31:11.198 Because we'll have to write it out every time 433 00:31:11.545 --> 00:31:14.635 So let's add something that will automate this 434 00:31:15.348 --> 00:31:15.978 Over here 435 00:31:18.348 --> 00:31:23.073 Let's create a function called SetState after void 436 00:31:23.736 --> 00:31:28.448 This will get EEnemyState newState 437 00:31:30.649 --> 00:31:32.307 Let's implement this here 438 00:31:39.000 --> 00:31:42.537 Here it is, at our State 439 00:31:42.537 --> 00:31:45.319 We will add newState 440 00:31:45.319 --> 00:31:48.424 And initialize CurrentTime as 0 441 00:31:48.424 --> 00:31:49.875 Let's do all these at once 442 00:31:50.479 --> 00:31:53.822 So by calling setState, this will be done automatically 443 00:31:55.297 --> 00:31:59.778 Let's now modify what we've done before 444 00:32:02.439 --> 00:32:05.584 This now takes care of resetting the time 445 00:32:06.218 --> 00:32:08.485 Now let's make it move towards the destination 446 00:32:10.257 --> 00:32:11.567 We're at 'Move' now 447 00:32:13.171 --> 00:32:14.447 So let's make it move 448 00:32:14.447 --> 00:32:18.682 When something moves, it moves to a direction 449 00:32:18.880 --> 00:32:21.016 And it moves towards a destination, a target 450 00:32:21.471 --> 00:32:22.397 So for Target 451 00:32:26.100 --> 00:32:29.423 GetActorLocation, let's use that 452 00:32:29.423 --> 00:32:35.706 And this minus my, or Me GetActorLocation 453 00:32:36.359 --> 00:32:38.115 That will give us the direction 454 00:32:38.858 --> 00:32:41.703 And let's use FVector to call this 'direction' 455 00:32:49.010 --> 00:32:52.799 And movement itself is implemented in the character 456 00:32:52.799 --> 00:32:56.716 At Enemy, so using AddMovementInput from above 457 00:32:56.716 --> 00:32:58.018 Will make it move 458 00:32:58.018 --> 00:32:59.595 Let's add our 'direction' here 459 00:33:04.427 --> 00:33:06.738 So we used this 'direction' here 460 00:33:06.738 --> 00:33:08.790 And here, this will automatically 461 00:33:08.790 --> 00:33:10.882 Normalize its size for use 462 00:33:11.199 --> 00:33:15.362 Meaning, there will be a certain length in here 463 00:33:15.520 --> 00:33:18.124 But to really make sure that it normalizes 464 00:33:18.520 --> 00:33:25.102 You can use getSafeNormal to keep the original 465 00:33:25.419 --> 00:33:28.353 And return a normalized copy 466 00:33:28.353 --> 00:33:29.378 So that's how it works 467 00:33:29.640 --> 00:33:33.661 And for this 'direction' it will have the actual distance 468 00:33:34.057 --> 00:33:36.057 So the distance from the target 469 00:33:37.920 --> 00:33:42.274 It's the Size of our 'direction' 470 00:33:42.739 --> 00:33:44.872 And at this function Size, it looks like this 471 00:33:45.674 --> 00:33:50.688 The equation for distance is, you multiply all parts 472 00:33:52.959 --> 00:33:55.978 Multiply everything and square root over everything 473 00:33:56.226 --> 00:33:58.126 This will give you the distance 474 00:33:59.058 --> 00:34:03.733 And if this is less than our attack range 475 00:34:04.060 --> 00:34:11.199 Or let's say this, dist or distance is less than attack range 476 00:34:11.377 --> 00:34:17.127 And that's transition to Attack, using SetState 477 00:34:18.850 --> 00:34:21.802 And for our Attack, just use Attack 478 00:34:28.050 --> 00:34:29.191 And let's move on 479 00:34:29.350 --> 00:34:32.629 For 'Attack', same thing, time passes 480 00:34:32.837 --> 00:34:33.749 CurrentTime 481 00:34:35.749 --> 00:34:44.447 From GetWorld, DeltaTimeSecond 482 00:34:45.477 --> 00:34:49.914 So this CurrentTime now 483 00:34:52.726 --> 00:34:55.977 It is larger than our AttackDelayTime 484 00:34:55.977 --> 00:34:57.837 Then our Enemy will attack 485 00:34:59.669 --> 00:35:01.338 For 'Attack', let's print some log 486 00:35:01.764 --> 00:35:03.368 UE_LOG 487 00:35:11.114 --> 00:35:13.947 My device froze; let's wait a bit 488 00:35:17.917 --> 00:35:20.439 And now, here, let's write 489 00:35:23.238 --> 00:35:27.085 "Attack!!!" for the text 490 00:35:29.479 --> 00:35:33.159 And for UE_LOG, this semicolon is not mandatory 491 00:35:33.159 --> 00:35:35.345 Because for this macro 492 00:35:36.018 --> 00:35:38.503 I'm sure this automatically adds a semicolon in itself 493 00:35:39.038 --> 00:35:40.243 So this is not mandatory 494 00:35:41.233 --> 00:35:43.063 Meaning, adding it won't do anything either 495 00:35:44.469 --> 00:35:46.385 Now, let's initialize CurrentTime 496 00:35:46.385 --> 00:35:49.251 CurrentTime is 0, to make it a cycle 497 00:35:49.855 --> 00:35:52.726 Because, this attack is a repeating action 498 00:35:53.617 --> 00:35:55.178 So that was for 'Attack' 499 00:35:55.178 --> 00:35:58.939 And aside from this, let's say Player ran away 500 00:35:58.939 --> 00:36:00.306 Then Enemy should follow 501 00:36:01.335 --> 00:36:06.726 So let's get the distance again here 502 00:36:06.726 --> 00:36:09.855 For that, we can do this 503 00:36:10.360 --> 00:36:13.324 float dist 504 00:36:14.008 --> 00:36:16.055 And we'd like to get that length again 505 00:36:16.332 --> 00:36:18.575 But see here, we already subtracted it here 506 00:36:18.575 --> 00:36:20.706 And we don't have any here; so we have to 507 00:36:21.518 --> 00:36:23.447 And, shall we do something different this time? 508 00:36:23.447 --> 00:36:28.247 For FVector, there is a function called 'Dist' 509 00:36:28.247 --> 00:36:31.744 You could use this, where you put two locations 510 00:36:31.971 --> 00:36:37.518 You can use that, or there is a function 511 00:36:38.320 --> 00:36:43.266 That uses information on how far the target is from me 512 00:36:43.503 --> 00:36:44.944 So at 'Me' 513 00:36:45.360 --> 00:36:49.736 Me, Distto... 514 00:36:50.360 --> 00:36:54.465 Or, GetDistanceTo, that's the function 515 00:36:54.465 --> 00:36:56.996 And you add 'Target' here 516 00:36:57.659 --> 00:36:58.895 Or you can reverse it 517 00:36:58.895 --> 00:37:01.233 Target can Me could exchange places 518 00:37:01.362 --> 00:37:03.063 You can move it around 519 00:37:04.577 --> 00:37:05.498 But I'll stick to this 520 00:37:06.053 --> 00:37:09.956 This is asking, how far is Me from Target? 521 00:37:10.758 --> 00:37:12.116 And it returns a value 522 00:37:13.037 --> 00:37:16.000 And we compare this to our attack range 523 00:37:16.000 --> 00:37:19.061 And if dist is larger than AttackRange 524 00:37:20.111 --> 00:37:21.557 It means that Player is running away 525 00:37:22.656 --> 00:37:24.498 So Enemy should follow 526 00:37:27.565 --> 00:37:33.119 SetState, and let's use 'Move' 527 00:37:36.768 --> 00:37:40.034 And now we would like some log printed 528 00:37:40.351 --> 00:37:43.816 But not UE_LOG; we'd like to expose it on the screen 529 00:37:44.687 --> 00:37:46.774 So here, let's try this 530 00:37:46.981 --> 00:37:51.367 For our Tick component, let's write it under there 531 00:37:52.199 --> 00:38:01.575 Here, to print the current state on the screen as a log 532 00:38:03.367 --> 00:38:06.486 Then, the current state should become text; FString 533 00:38:08.557 --> 00:38:10.740 strState 534 00:38:11.493 --> 00:38:12.701 This is an enum 535 00:38:12.701 --> 00:38:15.963 This enumerated type, this state 536 00:38:15.963 --> 00:38:17.610 This function can change it into string 537 00:38:17.610 --> 00:38:22.473 So here, write 'UEnum' 538 00:38:22.730 --> 00:38:25.682 Careful with the capitalization; it's lower case after two letters 539 00:38:26.177 --> 00:38:30.352 And then, 'asstring'... 540 00:38:31.546 --> 00:38:32.371 See here 541 00:38:32.371 --> 00:38:34.455 There is a function called GetValueAsString 542 00:38:35.158 --> 00:38:37.466 And we can add our State here 543 00:38:39.446 --> 00:38:42.032 Since this is a template, we can add angle bracket 544 00:38:42.032 --> 00:38:43.795 And add our template here 545 00:38:43.795 --> 00:38:45.493 Or we can just skip this part 546 00:38:45.998 --> 00:38:49.583 This is how we turn State into string 547 00:38:50.227 --> 00:38:53.536 Then what happens is, this sentence is printed 548 00:38:54.298 --> 00:38:55.677 Let's print this 549 00:38:57.449 --> 00:39:02.231 This function called DrawDebugString 550 00:39:02.231 --> 00:39:06.415 This allows for some string to be 551 00:39:06.504 --> 00:39:09.399 Printed on a particular spot on the screen 552 00:39:09.399 --> 00:39:12.417 So let's use this, GetWorld 553 00:39:15.120 --> 00:39:23.578 And second, this is the location 554 00:39:23.994 --> 00:39:30.974 With vector, so we use GetActorLocation from above 555 00:39:31.360 --> 00:39:33.968 And I'd like to print it a little to the top 556 00:39:33.968 --> 00:39:37.140 Around the character's head, so let's use Me, no... 557 00:39:38.120 --> 00:39:40.437 Let's add it as FVector 558 00:39:41.546 --> 00:39:45.387 'To the top' means z value, so 0, 0, 0 559 00:39:46.120 --> 00:39:46.929 And little to the top 560 00:39:50.159 --> 00:39:52.807 Shall we make it 50cm to the top? Like so 561 00:39:55.188 --> 00:39:58.114 And we print our strState here 562 00:39:59.897 --> 00:40:01.526 You can just leave it like this here 563 00:40:02.308 --> 00:40:06.485 But see here, there is this 'Duration' part 564 00:40:06.485 --> 00:40:09.566 So this shouldn't be -1, it should be 0 565 00:40:10.120 --> 00:40:12.974 So let's just do this part, like so 566 00:40:14.291 --> 00:40:16.849 We can add 0, and then 567 00:40:19.107 --> 00:40:22.448 We can assign a color; default is white 568 00:40:22.765 --> 00:40:25.919 FColor, and here is a list of colors 569 00:40:25.919 --> 00:40:27.357 Just add whatever color you like 570 00:40:27.357 --> 00:40:29.303 I'll try cyan 571 00:40:30.392 --> 00:40:35.459 Something bluish, and then here 572 00:40:36.518 --> 00:40:38.643 Duration is 0 573 00:40:38.643 --> 00:40:40.988 To add some shade, you can go with 'True' 574 00:40:41.760 --> 00:40:47.254 And whether to enlarge font size, and 1 means 1x 575 00:40:47.719 --> 00:40:49.490 And 1.nx will make it bigger by 1.n times 576 00:40:50.797 --> 00:40:53.548 I'll just keep it as it is 577 00:40:57.523 --> 00:40:59.588 And let's compile to see what happens 578 00:41:03.736 --> 00:41:06.058 Looking good, let's run it 579 00:41:10.778 --> 00:41:14.209 It's not moving, let's see... We forgot to add our component 580 00:41:15.239 --> 00:41:19.311 Our Enemy component, our FSM component should be here at Enemy 581 00:41:20.173 --> 00:41:22.235 So let's go to the header for Enemy 582 00:41:23.859 --> 00:41:28.932 And let's say UPROPRETY, EditAnywhere 583 00:41:28.932 --> 00:41:29.872 And then here 584 00:41:31.050 --> 00:41:35.151 class, UEnemyFSM 585 00:41:35.359 --> 00:41:39.219 And then, FSM 586 00:41:41.817 --> 00:41:43.689 Let's now implement this 587 00:41:44.135 --> 00:41:48.377 We need to create it, at the bottom of this constructor 588 00:41:50.198 --> 00:41:53.631 FSM, the same thing 589 00:41:53.631 --> 00:41:57.877 CreateDefaultSubobject 590 00:42:05.877 --> 00:42:09.859 And then let's add our UEnemyFSM 591 00:42:10.720 --> 00:42:12.429 The name, let's call it "FSM" 592 00:42:16.508 --> 00:42:21.073 In fact, if this doesn't contain other language, we can skip this 'TEXT' part 593 00:42:21.073 --> 00:42:22.075 But let's just keep it this way 594 00:42:22.808 --> 00:42:25.610 And now, let's compile it again 595 00:42:28.617 --> 00:42:31.981 For this Actor Component, we do not need to attach 596 00:42:32.753 --> 00:42:33.562 Not that we can 597 00:42:34.176 --> 00:42:36.374 And then, oh, there's an error 598 00:42:37.938 --> 00:42:39.455 Oh, we forgot to add the header 599 00:42:40.119 --> 00:42:41.946 Let's add our header like so 600 00:42:53.627 --> 00:42:55.615 And run, now our enemy is approaching 601 00:42:55.773 --> 00:42:59.130 'Move' and 'Attack', see how the state is changing 602 00:43:02.116 --> 00:43:06.109 Enemy is doing great, and then 603 00:43:07.258 --> 00:43:09.084 Now it is 'Damage' 604 00:43:09.510 --> 00:43:11.218 All the basic movements are looking great 605 00:43:12.396 --> 00:43:16.599 Now we need something to happen when Player attacks Enemy 606 00:43:17.044 --> 00:43:19.409 So at EnemyFSM 607 00:43:21.716 --> 00:43:23.870 Let's add a function to count that damage 608 00:43:25.830 --> 00:43:29.120 void OnDamageProcess 609 00:43:31.706 --> 00:43:32.553 Let's name it this way 610 00:43:32.553 --> 00:43:35.587 We could go with AttackDamage, but let's try this 611 00:43:36.627 --> 00:43:40.843 And then let's get the damage value as int 612 00:43:40.843 --> 00:43:46.637 Damage, that's the implementation 613 00:43:51.318 --> 00:43:55.196 For damage, this state 'Damage' can now change 614 00:43:55.879 --> 00:43:58.656 And to change it after getting damage, we need something 615 00:43:58.656 --> 00:43:59.976 We can't just change it right away 616 00:44:00.758 --> 00:44:03.725 We need this concept called HP, so that when it is exhausted 617 00:44:03.884 --> 00:44:05.826 Meaning, when HP hits 0, it goes to 'Die' 618 00:44:06.073 --> 00:44:07.724 And if HP is above 0, it goes to 'Damage' 619 00:44:08.546 --> 00:44:11.152 So now we need our HP part 620 00:44:11.152 --> 00:44:14.465 int HP, let's start with two 621 00:44:14.970 --> 00:44:16.778 Meaning, two hits and Enemy dies 622 00:44:18.698 --> 00:44:25.098 Here, let's subtract 'damage' from 'HP' 623 00:44:27.157 --> 00:44:36.075 If HP is bigger than 0, then setState, and it goes to 'Damage' 624 00:44:36.550 --> 00:44:38.669 And if it is not, if else 625 00:44:38.669 --> 00:44:42.639 Meaning, if it is below 0, it dies 626 00:44:42.639 --> 00:44:44.671 Then, setState and 627 00:44:46.077 --> 00:44:51.885 Actually, let me do this again 628 00:44:53.399 --> 00:44:55.466 'Die' and it goes there 629 00:44:57.607 --> 00:45:00.456 Now that this part is over, let's implement it 630 00:45:02.218 --> 00:45:03.637 For damage, let's do this 631 00:45:03.637 --> 00:45:04.847 First, time passes 632 00:45:08.627 --> 00:45:17.594 And if the time now is our damage delay time 633 00:45:17.594 --> 00:45:24.080 Then transition to 'Move', something like that 634 00:45:25.208 --> 00:45:28.029 And for when Enemy dies, I want to 635 00:45:28.237 --> 00:45:30.399 It should move down to the ground 636 00:45:30.399 --> 00:45:35.600 So move towards the bottom 637 00:45:36.907 --> 00:45:38.234 That's one thing we will implement 638 00:45:38.848 --> 00:45:40.959 Another thing is, we measure time 639 00:45:40.959 --> 00:45:42.456 So time passes 640 00:45:44.560 --> 00:45:52.320 And if current time is our death delay time 641 00:45:52.320 --> 00:45:55.697 Then we'd like to destroy 642 00:45:56.919 --> 00:46:01.520 Destroy who? 'Me', that's how it will look like 643 00:46:03.708 --> 00:46:05.535 Let's now start with 'Damage' 644 00:46:06.357 --> 00:46:07.626 Starting with implementation 645 00:46:07.943 --> 00:46:12.627 Here, CurrentTime GetWorld 646 00:46:15.480 --> 00:46:16.896 DeltaTimeSeconds 647 00:46:18.748 --> 00:46:20.609 And as it accumulates, time will pass 648 00:46:20.609 --> 00:46:24.006 As I told you before, when it accumulates and becomes 1, it means a second has passed 649 00:46:24.927 --> 00:46:28.792 So for current time... Then we need a variable here 650 00:46:28.792 --> 00:46:31.710 We need variables for 'damage delay' and 'death delay' 651 00:46:31.948 --> 00:46:35.315 Let's go to our header and add these two 652 00:46:35.315 --> 00:46:37.364 Like so, copy and paste twice 653 00:46:38.117 --> 00:46:40.382 This will be called 'DamageDelay' 654 00:46:41.917 --> 00:46:45.701 And 'DieDelay', let's name them like so 655 00:46:50.535 --> 00:46:53.057 Let's give our 'DamageDelay' two long seconds 656 00:46:56.248 --> 00:46:59.542 And 'DieDelay' too, let's add two seconds 657 00:47:00.948 --> 00:47:04.251 Should we do two seconds for 'Attack' too? It seems a little too fast 658 00:47:05.013 --> 00:47:06.087 Let's do two for all of these 659 00:47:10.800 --> 00:47:13.571 Now let's finish the other parts 660 00:47:13.928 --> 00:47:16.459 Now that we have our delay time 661 00:47:16.459 --> 00:47:19.223 CurrentTime is bigger 662 00:47:19.223 --> 00:47:21.877 Bigger than? Than our DamageDelay time 663 00:47:23.838 --> 00:47:27.280 Then transition to 'Move' 664 00:47:28.469 --> 00:47:33.818 Here, we just do setState and Move 665 00:47:37.520 --> 00:47:39.472 Then, when Enemy gets shot 666 00:47:39.472 --> 00:47:41.375 It will stand still for two seconds for now 667 00:47:42.108 --> 00:47:44.247 When we add animation later 668 00:47:44.247 --> 00:47:47.820 Two seconds is when it does some reaction and comes back 669 00:47:48.098 --> 00:47:49.783 Since we have no animation now 670 00:47:50.070 --> 00:47:51.953 Let's just implement it this way 671 00:47:52.765 --> 00:47:55.853 And let's finish our 'Die' state as well 672 00:47:55.853 --> 00:47:57.729 I'd like to move the character downward 673 00:47:58.749 --> 00:48:06.641 We can simply do so using P=P0 vt 674 00:48:07.829 --> 00:48:10.580 Let's start with our P0, FVector 675 00:48:11.639 --> 00:48:15.457 P0, this is GetActorLocation 676 00:48:17.550 --> 00:48:23.652 No, it should start from Me, and then GetActorLocation 677 00:48:25.078 --> 00:48:26.202 Now, let's create the 'vt' part 678 00:48:26.202 --> 00:48:30.894 'vt' for FVector is, it is downward 679 00:48:30.894 --> 00:48:34.040 And af FVector we have DownVector 680 00:48:34.040 --> 00:48:36.971 DownVector, this is how it looks like 681 00:48:36.971 --> 00:48:38.938 0, 0, -1 682 00:48:39.898 --> 00:48:42.030 And then we add some movement 683 00:48:42.228 --> 00:48:43.981 So let's give around 200 684 00:48:44.357 --> 00:48:47.714 We could subtract a variable, but let's just keep it here 685 00:48:48.159 --> 00:48:49.738 It looks like there are enough variables 686 00:48:50.401 --> 00:48:52.348 And we multiply ti by our DeltaTimeSeconds 687 00:48:52.615 --> 00:48:58.729 GetWorld, DeltaTimeSeconds 688 00:48:59.154 --> 00:49:02.143 And that's how we create our 'vt' part, right? 689 00:49:02.143 --> 00:49:06.612 This is 'v', direction multiplied by speed, for velocity 690 00:49:06.890 --> 00:49:09.288 And 't' is delta second 691 00:49:11.399 --> 00:49:12.438 Let's make it move now 692 00:49:12.952 --> 00:49:17.189 Me, SetActorLocation 693 00:49:19.439 --> 00:49:24.169 And then P0 vt, now the character moves downward 694 00:49:27.979 --> 00:49:30.399 And we will count for time to destroy it 695 00:49:30.706 --> 00:49:32.909 First, time should pass, so CurrentTime 696 00:49:36.265 --> 00:49:39.310 GetWorld, we can reuse this, right? 697 00:49:41.805 --> 00:49:42.508 And then 698 00:49:45.486 --> 00:49:46.448 Now let's get the time 699 00:49:46.448 --> 00:49:49.879 If CurrentTime is bigger than DieDelayTime 700 00:49:52.369 --> 00:49:56.594 And, if you press Ctrl K D 701 00:49:56.594 --> 00:49:58.224 It will align everything automatically 702 00:49:58.224 --> 00:49:59.760 So you could use it like that 703 00:49:59.760 --> 00:50:04.657 And then, this will be destroying myself 704 00:50:04.657 --> 00:50:06.257 So Me, Destroy 705 00:50:10.687 --> 00:50:12.913 You can implement it like so 706 00:50:14.230 --> 00:50:16.617 Let's run it to see how it looks like 707 00:50:19.298 --> 00:50:20.287 First, compile 708 00:50:24.918 --> 00:50:27.980 In fact, I forgot to work on the gun part 709 00:50:28.792 --> 00:50:30.725 For our Player, here 710 00:50:31.032 --> 00:50:34.647 Here, at OnIAFire, after 'Hit' 711 00:50:34.647 --> 00:50:39.607 If it hits our Enemy 712 00:50:39.607 --> 00:50:41.555 So, 'AEnemy' 713 00:50:44.216 --> 00:50:48.008 FSM of AEnemy 714 00:50:50.820 --> 00:50:52.869 OnDamageProcess 715 00:50:54.810 --> 00:50:56.517 It will call this function like so 716 00:50:56.517 --> 00:51:00.462 Damage, one point 717 00:51:01.719 --> 00:51:05.775 One point of damage for Enemy 718 00:51:05.775 --> 00:51:08.268 It will give a point of damage 719 00:51:09.426 --> 00:51:15.186 And this is how it works, basically, and for that 720 00:51:15.186 --> 00:51:20.000 We need to first know whether it hit Enemy; and to do so 721 00:51:20.000 --> 00:51:26.719 At hitInfo we have GetActor, which is the one that is hit, the other's actor 722 00:51:26.719 --> 00:51:32.520 We can cast this to double check, so let's cast 723 00:51:33.000 --> 00:51:37.439 AEnemy, let's cast like so 724 00:51:39.756 --> 00:51:42.159 Also, add the header like so 725 00:51:42.407 --> 00:51:47.087 Let me bring it up so that I can show you how I'm adding the header 726 00:51:47.998 --> 00:51:49.107 I added this part 727 00:51:57.808 --> 00:52:00.925 And now, Auto, enemy to get this 728 00:52:01.787 --> 00:52:04.887 Since this is the pointer, this will be a better way to write it out 729 00:52:04.887 --> 00:52:06.506 We could just say auto but 730 00:52:07.010 --> 00:52:11.592 Yes, auto*enemy; and for reference, this is how it works 731 00:52:12.404 --> 00:52:13.673 So let's use that 732 00:52:17.867 --> 00:52:20.599 And if Enemy is not null 733 00:52:20.599 --> 00:52:22.335 Then it is indeed our Enemy 734 00:52:23.869 --> 00:52:25.189 So let it try casting like so 735 00:52:28.812 --> 00:52:32.072 And at Enemy, we have FSM 736 00:52:33.498 --> 00:52:38.371 We could approach it right away like this 737 00:52:38.816 --> 00:52:41.533 But actually, this is not the best way to do this 738 00:52:41.810 --> 00:52:45.516 For Object-Oriented Programming (OOP), approaching the other's attribute 739 00:52:45.516 --> 00:52:48.648 And then from there, another attribute, and so on 740 00:52:48.648 --> 00:52:51.577 This is not an optimal way of processing a value at OOP 741 00:52:52.617 --> 00:52:57.239 So a better way is, we implement our v at this Enemy header 742 00:52:57.239 --> 00:52:59.833 And then we could call it right here 743 00:53:00.358 --> 00:53:07.077 So let's create the function, void TakeDamage 744 00:53:13.536 --> 00:53:16.137 Let's implement that 745 00:53:18.360 --> 00:53:20.964 So at Takedamage 746 00:53:23.449 --> 00:53:31.414 We'll deliver this damage to OnDamageProcess at FSM 747 00:53:31.592 --> 00:53:33.818 This is more Object-Oriented 748 00:53:35.990 --> 00:53:39.523 And outside, we can call TakeDamage at Enemy 749 00:53:41.038 --> 00:53:42.629 Let's implement it like that 750 00:53:43.570 --> 00:53:45.878 But we may use TakeDamage elsewhere again 751 00:53:45.878 --> 00:53:48.661 So let's add something like 'OnMy' 752 00:53:50.136 --> 00:53:52.135 Let's modify the name like so 753 00:53:55.798 --> 00:53:58.279 So for Player, we can call 754 00:54:01.259 --> 00:54:04.237 OnMyTakeDamage from Enemy 755 00:54:04.237 --> 00:54:05.097 That will be one point 756 00:54:09.770 --> 00:54:11.185 Save everything 757 00:54:11.760 --> 00:54:14.046 Compile, and let's see how it works 758 00:54:24.225 --> 00:54:27.228 Moving well, and when it gets hit, it stops 759 00:54:27.367 --> 00:54:28.890 And after two seconds, it moves again 760 00:54:29.306 --> 00:54:32.394 And then another shot; it should die, it should move down 761 00:54:32.899 --> 00:54:34.482 It is destroyed but it does not move down 762 00:54:34.482 --> 00:54:40.116 This is because CapsuleComponent is hitting the ground 763 00:54:41.008 --> 00:54:42.612 So let's finish that part 764 00:54:43.375 --> 00:54:46.634 This is done here, now at EnemyFSM 765 00:54:47.436 --> 00:54:49.948 'Die' part is over here 766 00:54:50.681 --> 00:54:53.916 From OnDamageProcess to 'Die' here 767 00:54:54.718 --> 00:55:00.313 At 'Me' there is this capsule, CapsuleComponent 768 00:55:01.917 --> 00:55:05.743 And its SetCollisionEnabled 769 00:55:06.644 --> 00:55:09.386 Let's change it into NoCollision like this 770 00:55:09.525 --> 00:55:11.925 Because we won't be using it, since it's dead 771 00:55:12.667 --> 00:55:17.187 To use this, we need this CapsuleComponent, right? 772 00:55:17.187 --> 00:55:19.352 Then this needs a header 773 00:55:19.609 --> 00:55:21.520 So let's add it here 774 00:55:21.807 --> 00:55:26.540 CapsuleComponent, and add the header like so 775 00:55:27.708 --> 00:55:30.257 And there is no error; let me show you as well 776 00:55:31.405 --> 00:55:34.835 At Components, we have CapsuleComponent 777 00:55:40.689 --> 00:55:41.810 That's how you do it 778 00:55:47.768 --> 00:55:48.897 Then it will remove the error 779 00:55:50.214 --> 00:55:52.206 Let's compile to see the result 780 00:55:59.528 --> 00:56:01.826 Boom, boom, and it moves downward 781 00:56:01.945 --> 00:56:04.286 And destroyed, like so 782 00:56:06.008 --> 00:56:08.621 And let's actually remove the bullet here 783 00:56:08.621 --> 00:56:10.511 We do not need our bullet actor just yet 784 00:56:11.581 --> 00:56:12.481 And that's it 785 00:56:13.679 --> 00:56:17.254 Let's summarize what we've learned this chapter 786 00:56:17.893 --> 00:56:21.393 Creating Enemy Actor and Distinguishing FSM-Based State Creating Enemy Actor How to apply appearance of enemy actor: Create enemy using Quinn 787 00:56:21.393 --> 00:56:24.903 Distinguishing FSM-Based State Finite State Machine: State, Condition, Transition How to branch the current state from Tick to process the enemy actor state 788 00:56:24.903 --> 00:56:28.853 Implementing Actions for Each FSM-Based State Finite State Machine Ups: Each action can be implemented separately Downs: Complex, loses readability 789 00:56:28.853 --> 00:56:32.775 Idle, Move, Attack, Damage, Die States Separate each state and implement each individually Allow for appropriate transition under certain conditions