WEBVTT

00:06.840 --> 00:08.040
Welcome back.

00:08.070 --> 00:14.280
So now that we have visuals looking pretty good for our Arcane Shards ability, it's time to start thinking

00:14.280 --> 00:15.480
about damage.

00:15.660 --> 00:17.250
Now for Arcane Shards.

00:17.250 --> 00:19.410
I'd like to have radial damage.

00:19.410 --> 00:21.420
I'd like to be able to cast this.

00:21.420 --> 00:24.960
And for each of these shards, I'd like to cause more damage.

00:24.960 --> 00:31.590
The closer my enemies are to those individual shards, and they'll take a little bit of damage as their

00:31.590 --> 00:34.380
distance increases to those shards.

00:34.380 --> 00:37.230
So radial damage with a falloff.

00:37.230 --> 00:43.890
And if we're going to be implementing damage that has a falloff, we're going to need some parameters.

00:44.160 --> 00:47.760
Now I'd like to take a look at one engine function.

00:47.760 --> 00:55.380
If I double shift to search I'm going to search for radial damage with falloff.

00:57.210 --> 00:59.400
And we have a gameplay statics function.

00:59.400 --> 01:02.040
Apply radial damage with falloff.

01:02.890 --> 01:05.680
Now this is an interesting function.

01:05.680 --> 01:09.640
In fact, Unreal Engines damage system itself is quite interesting.

01:09.640 --> 01:16.810
It has damage capabilities, but it doesn't really have a built in concept of health.

01:16.810 --> 01:22.720
You're supposed to do with these damage functions what you need for your project.

01:22.720 --> 01:31.630
So apply radial damage with falloff is just going to perform this algorithm where it actually sees which

01:31.630 --> 01:33.700
actors are overlapping with it.

01:33.700 --> 01:40.360
And for any actors overlapping with it, it's going to if we scroll down to the bottom called Take Damage

01:40.360 --> 01:40.900
on it.

01:40.900 --> 01:50.080
So it calculates the falloff using its own algorithm, it performs the sphere query, similar to what

01:50.080 --> 01:53.560
we've done in one of our functions and our function library.

01:53.560 --> 01:55.540
And then it ends up calling take damage.

01:55.540 --> 02:02.170
And take damage is a function that is virtual and can be overridden in any actor.

02:02.170 --> 02:10.120
And so it's up to us to receive that value passed through for the damage calculated and take damage.

02:10.120 --> 02:10.930
So apply.

02:10.930 --> 02:13.780
Radial damage with falloff is something we can use.

02:13.780 --> 02:21.220
We can take advantage of the built in engine capabilities, and then we can choose how to handle that

02:21.220 --> 02:21.670
damage.

02:21.670 --> 02:25.630
But apply radial damage with falloff requires some parameters.

02:25.630 --> 02:31.660
It takes in a base damage amount, and it basically nerfs that damage depending on how far away the

02:31.660 --> 02:39.790
target is from some origin, and it uses two spheres, a minimum and a maximum sphere.

02:39.790 --> 02:45.610
One sphere has an inner radius, one sphere has an outer radius, and any actors that are within that

02:45.610 --> 02:53.620
inner radius get the full amount of damage, that base damage passed in, and any actors that are outside

02:53.620 --> 03:00.730
of damage outer radius, they get the minimum amount of damage passed in, and then any actors in between

03:00.730 --> 03:08.260
those two radii have base damage with some falloff, some percentage taken off of that damage depending

03:08.260 --> 03:10.420
on the falloff chosen.

03:10.420 --> 03:12.280
And there are different types of falloff.

03:12.280 --> 03:19.000
There's linear fall offs, other types of fall offs that are smoother curves, such as cubic mathematics

03:19.000 --> 03:19.930
functions.

03:19.930 --> 03:25.240
And if you want the details, you can always look at the implementation here in this function to see

03:25.240 --> 03:29.350
exactly how that radial damage is calculated.

03:29.710 --> 03:33.940
But if we're going to call this function we need some of these parameters.

03:33.940 --> 03:36.910
Notice there's a damage falloff parameter.

03:36.910 --> 03:42.970
And if we look at how that's used we see that it's passed into radial damage params.

03:46.810 --> 03:52.870
If we go to this, we see that it has these base damage, minimum damage, these parameters.

03:52.870 --> 03:53.650
Right.

03:53.920 --> 03:59.680
And it also has get damage scale, which returns the damage done at a certain distance.

03:59.680 --> 04:02.110
This is defined in damage events.

04:04.530 --> 04:08.400
If we look for jet damage scale, it has a distance from epicenter.

04:09.390 --> 04:11.550
And it checks the damage fall off here.

04:11.550 --> 04:18.600
Sees if it's equal to zero, then it says no fall off or inside an a radius means full effect.

04:18.990 --> 04:20.280
It returns one.

04:20.280 --> 04:21.750
This is a scale by the way.

04:21.750 --> 04:24.090
So we're scaling damage by this.

04:24.090 --> 04:27.450
But notice here it's calculating an interpolated scale.

04:27.450 --> 04:31.770
It's creating a damage scale set to one minus some value.

04:31.770 --> 04:33.240
This is a ratio.

04:33.240 --> 04:37.380
It's the validated distance minus validated distance inner radius.

04:37.380 --> 04:44.760
So the space in between the inner radius and this distance divided by the validated outer radius minus

04:44.760 --> 04:46.080
validated inner radius.

04:46.080 --> 04:48.360
So it's scaling outer radius.

04:48.360 --> 04:54.390
So it's setting damage scale equal to one minus this ratio here which means damage scale is going to

04:54.390 --> 04:56.370
probably be less than one.

04:56.580 --> 05:00.510
And then it takes that damage scale and it calls power on it.

05:00.510 --> 05:05.400
It takes damage scale and raises it to the power of the damage fall off.

05:05.400 --> 05:10.260
So we're taking a value that's either one or smaller.

05:10.260 --> 05:14.010
So smaller than one say 0.25 for example.

05:14.010 --> 05:15.750
And we're raising it to a power.

05:15.750 --> 05:20.610
And if that power is smaller than one then damage scale is going to get smaller.

05:20.610 --> 05:21.630
I mean, think about it.

05:21.630 --> 05:23.940
Let's say damage scale is 0.25.

05:24.180 --> 05:26.640
And let's say damage fall off is two.

05:26.670 --> 05:29.280
Well, 0.25 times 0.25.

05:29.310 --> 05:32.340
That's a quarter of a quarter, right?

05:32.340 --> 05:35.550
If it was 0.5 then that would be half of a half.

05:35.550 --> 05:36.660
What's half of a half?

05:36.660 --> 05:37.410
That's a quarter.

05:37.410 --> 05:43.770
So raising a value that's less than one to a power that's greater than one is going to make it smaller.

05:43.770 --> 05:50.670
So if we just want to have this linear fall off, we can just have a damage fall off of one.

05:50.670 --> 05:55.110
Otherwise if we want a harsher fall off we can use a higher value for damage fall off.

05:55.110 --> 05:57.090
So that's how damage fall off works.

05:57.090 --> 06:04.980
And now we understand that if we're going to be using our built in apply radial damage with fall off

06:04.980 --> 06:08.250
and responding to it, then we're going to need some parameters.

06:08.250 --> 06:15.630
Those parameters are going to be a radial damage minimum, a radial damage origin, a radial damage

06:15.630 --> 06:19.320
inner and outer radius, a fall off if we want that.

06:19.320 --> 06:21.480
Otherwise we can hard code one.

06:21.480 --> 06:25.920
And then we have a bunch of other things, such as a damage type class.

06:25.920 --> 06:32.040
Now we're using gameplay tags to identify our damage types, but damage types are essentially classes

06:32.040 --> 06:36.150
that you only add static functions to if you add anything to them.

06:36.150 --> 06:40.080
Because we never instantiate instances of them, we just use the class.

06:40.080 --> 06:44.820
So you can use it as a static class, like an identifier, and add static functions.

06:44.820 --> 06:48.960
If you want, you could subclass this and give it a gameplay tag.

06:48.960 --> 06:53.010
I don't think we really have any uses for it in this project.

06:53.010 --> 06:58.680
And of course we have a damage prevention channel if you want to prevent damage for any specific channel.

06:58.680 --> 07:03.720
So we're going to create some radial damage parameters.

07:03.720 --> 07:06.870
And I'd like to add those to a couple of our types.

07:06.870 --> 07:08.640
I'm going to go to our ability types.

07:08.640 --> 07:10.200
We have CP here.

07:10.200 --> 07:12.180
And I'll open the header file.

07:12.180 --> 07:15.720
And we have f damage effect params.

07:15.720 --> 07:19.050
I'd like to add some parameters for radial damage here.

07:19.050 --> 07:21.300
And we also have the effect context.

07:21.300 --> 07:27.090
And this will be a good way for us to carry radial damage params with us throughout the pipeline if

07:27.090 --> 07:31.200
we want to access it, say in exec calc damage.

07:31.560 --> 07:33.840
So that's what I'd like to do in this video.

07:33.840 --> 07:39.630
I'd like to create some radial damage parameters, and we're going to start by adding them to f damage

07:39.630 --> 07:40.830
effect params.

07:41.160 --> 07:45.690
So down here at the bottom I'm going to add a few parameters.

07:45.690 --> 07:50.490
One will be a boolean and I'm going to call this b is radial damage.

07:50.520 --> 07:52.320
And it'll be false by default.

07:52.320 --> 07:56.280
So if we never set it then we'll never have radial damage.

07:56.280 --> 08:02.310
And I'll make it blueprint red right now in addition to this boolean that we can check to see if we

08:02.310 --> 08:07.410
even have radial damage, we can have a few radial damage parameters.

08:07.770 --> 08:10.440
We're going to have a float.

08:10.440 --> 08:15.210
And this can be our radial damage inner radius.

08:16.350 --> 08:24.150
We can have a float radial damage outer radius, and we can initialize these both to zero.

08:31.290 --> 08:35.490
And we can also have a radial damage origin, which can be an f vector.

08:35.490 --> 08:37.500
So we'll make an f vector.

08:37.500 --> 08:39.900
Radial damage origin.

08:42.180 --> 08:45.030
We'll initialize it to the zero vector.

08:49.940 --> 08:52.940
And with that, we should have enough information.

08:53.390 --> 08:59.750
Now, if we really wanted to, we could have a radial damage minimum amount, and that could be separate

08:59.750 --> 09:02.660
from our base damage that we have here.

09:02.660 --> 09:07.550
But I'm just going to use zero for my minimum radial damage.

09:07.550 --> 09:10.460
And with that let's add blueprint read.

09:10.460 --> 09:15.110
Write to all of these in case we want to set them from within.

09:15.110 --> 09:15.680
Blueprint.

09:15.680 --> 09:23.900
If we make one of these structs now that we have these for radial damage properties, we're going to

09:23.900 --> 09:30.560
want to make sure that we're setting these in our damage effect params when we make them with our gameplay

09:30.560 --> 09:33.440
ability, or a damage gameplay ability.

09:33.770 --> 09:38.210
And that means or a damage gameplay ability should have the option to be radial.

09:38.240 --> 09:43.730
You see, we want radial damage for arcane shards, but for that reason I want our whole system to be

09:43.730 --> 09:45.710
capable of radial damage.

09:45.710 --> 09:50.270
And that way when we have another radial damage spell, we don't have to reinvent the wheel.

09:50.570 --> 09:53.090
So I'm going to go into aura damage gameplay ability.

09:53.120 --> 09:54.620
Here's the cpp file.

09:54.620 --> 09:56.480
I'm going to go into the header as well.

09:58.430 --> 10:01.760
And we're going to add some radial damage parameters.

10:01.760 --> 10:07.550
And they're going to be identical to our damage effect parameters, namely these four here.

10:07.550 --> 10:09.290
So I'm just going to copy them.

10:09.290 --> 10:13.730
And over here in aura damage gameplay ability I'm going to go ahead and paste them.

10:13.730 --> 10:17.930
The only difference is I'm only going to make them edit defaults only.

10:17.930 --> 10:19.880
We don't need them to be blueprint read write.

10:19.880 --> 10:22.190
So I'm going to change their U properties.

10:24.880 --> 10:31.690
Now I'm going to take these four and set them in our aura damaged gameplay ability function make damage

10:31.690 --> 10:33.940
effect params from class defaults.

10:33.940 --> 10:40.270
We're going to go ahead and set these, but really only if this is radial damage.

10:40.270 --> 10:44.860
So we're going to first check if B is radial damage.

10:44.860 --> 10:49.240
If that's true then we can go ahead and set the radial damage parameters.

10:49.240 --> 10:50.860
We're going to say params.

10:51.970 --> 10:57.220
Dot b is radial damage equals B is radial damage.

10:57.220 --> 10:58.750
We'll carry that across.

10:58.750 --> 11:02.680
We'll have params dot radial damage origin.

11:02.680 --> 11:08.590
We'll set that to radial damage origin and two more params dot radial damage inner radius.

11:09.100 --> 11:15.400
We'll set that to radial damage inner radius and params dot radial damage outer radius.

11:15.400 --> 11:18.280
We'll set that to radial damage outer radius.

11:18.790 --> 11:25.510
And now our function for making these params sets them based on the ability class itself.

11:25.510 --> 11:30.310
And then we can carry those along whenever we need to apply a gameplay effect.

11:31.210 --> 11:36.910
Now, if we're going to apply a gameplay effect and make use of these, we need to decide how.

11:37.300 --> 11:40.060
I'd like to set them in the effect context.

11:40.060 --> 11:46.180
And that way we can check the effect context to see if it's radial damage at any point in our damage

11:46.180 --> 11:47.050
pipeline.

11:47.470 --> 11:53.920
Another alternative is to make these set by color magnitudes, but I'm opting for setting them in the

11:53.920 --> 11:55.420
effect context.

11:55.420 --> 12:01.390
And that way we don't have to crowd up our gameplay effect spec with too many set by color magnitudes,

12:01.390 --> 12:05.650
and we don't have to create too many gameplay tags just for those reasons.

12:06.010 --> 12:12.850
So I'm going to go back to aura ability types, and we're going to add these into our gameplay effect

12:12.850 --> 12:14.110
context.

12:14.840 --> 12:17.300
So we're going to have four new variables here.

12:17.300 --> 12:23.960
Which means we're going to have a few steps including determining how these should be serialized.

12:24.530 --> 12:29.330
So just after knockback force we're going to add these four variables.

12:29.330 --> 12:37.130
And if I'd like to be lazy I could go back to aura damage gameplay ability or just scroll up to.

12:38.500 --> 12:41.920
F damage effect params and I can just copy them from here.

12:41.950 --> 12:45.970
Starting it is radial damage so I'm going to do that.

12:46.610 --> 12:48.440
And I'm going to paste them down here.

12:48.440 --> 12:51.110
Only they're not going to be blueprint read write.

12:51.110 --> 12:53.090
They're just going to be you properties.

12:53.450 --> 12:57.740
So now we have a new bool two floats and an F vector.

12:57.740 --> 12:59.900
And they're all initialized.

13:00.260 --> 13:07.250
So because these are protected we're going to need getters and setters for each of them starting with

13:07.250 --> 13:09.950
the Boolean and working our way down.

13:10.280 --> 13:12.650
So I'm just going to add the getter here.

13:13.010 --> 13:22.670
It's going to be bool is radial damage const return B is radial damage.

13:23.580 --> 13:26.160
And while I'm at it, I'll make this better as well.

13:26.190 --> 13:40.740
Void set is radial damage, takes a bool, be in is radial damage, and sets B is radial damage to be

13:40.740 --> 13:42.690
in is radial damage.

13:42.990 --> 13:45.390
So this is a bit monotonous.

13:45.390 --> 13:50.310
So I can time lapse creating the getters and setters for the remaining three.

13:50.310 --> 13:51.720
So let's do that.

14:31.990 --> 14:32.620
All right.

14:32.620 --> 14:34.660
So I have my getters and my setters.

14:34.660 --> 14:39.160
Now the next step is to net serialize these.

14:39.160 --> 14:42.460
Now I'm going to go into our ability types Datcp.

14:42.670 --> 14:47.530
And we're going to flip our bits by checking our member variables.

14:47.530 --> 14:52.600
Now the first one I'm going to check here is is radial damage.

14:52.600 --> 14:59.950
So I'm going to say if B is radial damage then I'm going to flip the 16th bit.

15:00.700 --> 15:04.240
And I'm not going to bother flipping any of the other bits.

15:04.240 --> 15:06.640
If is radial damage is false.

15:06.640 --> 15:14.260
So we're going to check not only are these zero or the zero vector, but we're also going to check is

15:14.260 --> 15:16.120
radial damage as well.

15:17.300 --> 15:18.170
We can do that.

15:18.170 --> 15:20.000
We can also just check them here.

15:20.000 --> 15:22.100
Inside of B is radial damage.

15:22.100 --> 15:29.990
If we wanted to do that, we could say if radial damage inner radius is greater than zero.

15:32.570 --> 15:35.450
In that case, we can flip the 17th bit.

15:36.940 --> 15:39.610
We can also check the outer radius.

15:40.970 --> 15:43.010
So we could change this to outer.

15:45.400 --> 15:55.450
And flip the 18th bit, and then we can finally check if radial damage origin dot is zero and we can

15:55.450 --> 15:56.650
put a knot here.

15:56.650 --> 16:02.200
So if it's not zero then we'll flip the 19th bit just like that.

16:02.200 --> 16:07.330
Now if you don't like nesting them, if it seems a little bit confusing, you could take these out and

16:07.330 --> 16:14.050
just check both these conditions and have an end and check B is radial damage.

16:14.050 --> 16:15.460
You could do it that way too.

16:15.460 --> 16:21.670
So with that we can now serialize and we need serialized bits to accommodate now for 19 bits.

16:21.670 --> 16:24.100
So we're going to pass a 19 into that.

16:25.680 --> 16:32.940
And after that we can check these new bits 16, 17, 18 and 19.

16:32.970 --> 16:35.640
So let's go all the way down and check those.

16:36.440 --> 16:41.240
So first we're going to check if rep bits.

16:41.570 --> 16:44.450
We're going to use and bitwise and that is.

16:45.260 --> 16:47.510
One left shift 16.

16:49.570 --> 16:59.290
And while I'm at it, I'm just going to copy this before I put anything in there and check 17, 18 and

16:59.290 --> 17:00.160
19.

17:01.180 --> 17:05.320
So if we flipped 16, we can go back up and look.

17:05.320 --> 17:06.670
That's going to be.

17:07.520 --> 17:09.440
For is radial damage.

17:10.160 --> 17:14.330
So what we'll do is we'll take the archive.

17:15.400 --> 17:18.400
And will archive be is radial damage.

17:19.870 --> 17:24.580
Now, if this bit has not been flipped, there's no point in checking these other four.

17:24.610 --> 17:29.590
So if you wanted to, you could also put these inside here as well.

17:30.200 --> 17:38.090
Now we can check if rep bits has its 17th bit flipped and the 17th bit, if we remind ourselves up here

17:38.090 --> 17:40.250
is radial damage inner radius.

17:40.250 --> 17:42.410
So we can archive that float.

17:44.140 --> 17:48.580
So we'll say are radial damage inner radius.

17:49.440 --> 17:52.320
And 18 is the outer radius.

17:52.320 --> 17:54.630
So are radial damage.

17:54.630 --> 17:56.040
Outer radius.

17:56.400 --> 17:58.980
And now for the origin which is an f vector.

17:58.980 --> 18:01.710
So how are we going to handle the f vector.

18:01.740 --> 18:03.510
Well we've seen that we can handle.

18:03.510 --> 18:07.470
Net serialize for f vectors using the f vector.

18:07.470 --> 18:08.460
Net serialize.

18:08.460 --> 18:14.430
So we're going to do that with our radial damage origin.

18:14.430 --> 18:15.180
We're going to call.

18:15.180 --> 18:16.410
Net serialize.

18:16.410 --> 18:18.720
And we're going to pass in the archive.

18:18.720 --> 18:21.240
We're going to pass in the map and be out.

18:21.240 --> 18:22.050
Success.

18:22.810 --> 18:27.340
And with that, we're serializing our radial damage parameters.

18:28.070 --> 18:30.530
Okay, so that's a good start.

18:30.530 --> 18:37.970
We now know that our effect context can accommodate for radial damage parameters, as well as our f

18:37.970 --> 18:40.280
damage effect parameters as well.

18:40.280 --> 18:44.660
And our damage gameplay ability now has radial parameters.

18:44.660 --> 18:47.330
And we'll just set that B is radial damage.

18:47.330 --> 18:49.250
It's set to false by default.

18:49.250 --> 18:52.910
And if we never set it to true then the context doesn't carry it along.

18:52.910 --> 18:55.520
It doesn't even serialize it for replication.

18:55.520 --> 19:03.020
So we're not picking up any bandwidth across the net if we're not using these parameters.

19:03.020 --> 19:05.270
And if B is radial, damage is false.

19:05.270 --> 19:07.610
We don't serialize any of these four.

19:07.610 --> 19:10.460
So that's a nice optimization.

19:11.080 --> 19:14.410
So with that we can go ahead and compile.

19:14.410 --> 19:16.060
Looks like I have the editor open.

19:16.060 --> 19:18.520
I'm going to close it and just compile.

19:18.520 --> 19:20.290
Make sure I have no errors.

19:21.620 --> 19:27.950
And with that, we're now set up and ready to use our radial damage parameters.

19:27.950 --> 19:29.270
And we'll do that next.
