WEBVTT

00:07.010 --> 00:08.150
Welcome back.

00:08.150 --> 00:14.750
Now we're almost complete with all of the main mechanics of this game project, except for when aura

00:14.750 --> 00:15.320
dies.

00:15.320 --> 00:19.160
When aura dies, she ragdolls, sure, but that's it.

00:19.160 --> 00:26.570
And from that point on, aura is just laying on the floor and you have to hard exit the game, right?

00:26.780 --> 00:30.800
So what we're going to do is determine what happens when aura dies.

00:30.800 --> 00:33.980
And I'm fine with just a simple timer.

00:33.980 --> 00:40.970
Wait for a few seconds and then respawn at the last checkpoint or the beginning of the game if there

00:40.970 --> 00:42.740
is no checkpoint saved.

00:42.740 --> 00:46.250
So this is perhaps going to start in the game mode.

00:46.250 --> 00:52.400
I'm going to open Aura Game Mode base, and we're going to make a new function here for when a player

00:52.400 --> 00:53.210
dies.

00:53.210 --> 00:55.070
So this will be a void function.

00:55.070 --> 00:57.140
And I'm going to call this player died.

00:57.140 --> 00:58.220
It's going to be public.

00:58.220 --> 01:05.990
And I'm going to pass in an A character just in case we want something to do with that dead character.

01:06.200 --> 01:07.520
This is really for the future.

01:07.520 --> 01:13.460
I don't really have much I want to do with the dead character, other than just have it in case we want

01:13.460 --> 01:14.000
it.

01:14.480 --> 01:23.540
Now, if the player dies, I want to first of all, load up our save game object and see what our map

01:23.540 --> 01:27.380
is that we last saved our progress at.

01:27.380 --> 01:30.560
Which means I need a you load screen save game.

01:30.560 --> 01:34.130
I'll call this save game and I'll retrieve end game.

01:34.130 --> 01:38.180
Save data and recall what this function does for us.

01:38.180 --> 01:40.460
Retrieve end game.

01:40.460 --> 01:41.060
Save data.

01:41.060 --> 01:48.140
Gets the game instance, gets the load slot, name and index from it, and simply gets save slot data

01:48.140 --> 01:55.730
with that name and index and get save slot data is just going to load a game from slot if it exists.

01:55.730 --> 02:01.100
Otherwise it'll create a new one, cast it to a load screen, save game and return it.

02:01.100 --> 02:08.150
So that's all we're doing is getting that save game object, and I'd like to see if it's a valid pointer

02:08.150 --> 02:10.160
and basically return if it's not.

02:10.160 --> 02:11.930
So if not is valid.

02:12.670 --> 02:15.220
Save game, we can return.

02:16.630 --> 02:22.540
And after that we can simply travel to the level that's in that save game.

02:22.540 --> 02:24.280
Now we can do this with you.

02:24.280 --> 02:25.630
Gameplay statics.

02:25.630 --> 02:30.370
Open level and open level first requires a world context object.

02:30.370 --> 02:31.210
How convenient.

02:31.210 --> 02:37.090
We have the dead character and we can convert the map asset name to an F name.

02:37.090 --> 02:41.800
As this does require an F name, we can get our save game object.

02:42.610 --> 02:46.660
And get the map asset name and we can travel to it now.

02:46.690 --> 02:48.580
Dead character is an A character.

02:48.580 --> 02:50.560
We have to include the character type.

02:50.560 --> 02:57.880
Our game mode thus far has not used anything of the sort, so we need to use game framework character

02:57.880 --> 03:01.720
dot h if that is to be a defined type.

03:01.720 --> 03:03.040
Okay, now this is great.

03:03.040 --> 03:08.380
The game mode has a way to travel us to the level saved in that save game object.

03:08.380 --> 03:12.190
But the problem is this is the map asset name.

03:12.190 --> 03:15.490
And we're not actually saving that in all cases.

03:15.490 --> 03:19.450
In fact, the only time we're setting this is from our map entrance.

03:19.450 --> 03:26.140
If we go to the checkpoint folder into map entrance dot cp, we'll see that we're calling the save world

03:26.140 --> 03:29.530
state function, passing in an asset name for the map.

03:29.530 --> 03:32.950
But this is only for when we're traveling to a new map.

03:32.950 --> 03:38.500
If we save at a checkpoint, we're actually passing in nothing for that second parameter, which means

03:38.500 --> 03:40.540
no map name will be saved.

03:40.540 --> 03:43.720
So it's kind of important that we save that map name.

03:43.720 --> 03:46.900
I think we should do that in the checkpoint dot CP.

03:47.080 --> 03:53.020
As we're saving the world state, we should save the name of the current level, which we can always

03:53.020 --> 03:55.120
get because we can get the world.

03:55.120 --> 04:01.690
We can make a const you world pointer and initialize it with get world, and we can get its name.

04:01.690 --> 04:07.750
We can make an f string called map name, and we can use the world which I didn't give a name.

04:07.750 --> 04:09.070
I'm going to call it world.

04:09.070 --> 04:13.900
We can use this world and call get map name.

04:13.930 --> 04:20.560
Of course it has the streaming levels prefix, so we have to take map name and call remove from start

04:20.560 --> 04:23.470
world streaming levels prefix.

04:23.470 --> 04:26.890
And now we have the asset name which we can pass in.

04:26.890 --> 04:30.790
So we can pass in map name here.

04:31.690 --> 04:32.740
Now that's great.

04:32.740 --> 04:36.370
But there's also another thing that we have to realize.

04:36.370 --> 04:44.350
We have to realize that when we create a new game, we're not really initializing the map asset name.

04:44.350 --> 04:47.800
We're not saving anything to our save game object at that point.

04:47.800 --> 04:50.830
So we need to save the map asset name.

04:50.830 --> 04:54.160
We have to save it when we create a new slot.

04:54.160 --> 04:59.230
So we can go to ViewModel load screen and new slot button pressed.

04:59.230 --> 05:06.490
Here is where we are setting properties on our slot that we're going to save in our save game object,

05:06.490 --> 05:13.510
because we're passing in to our Or game mode, that slot when we call save slot data.

05:13.510 --> 05:20.680
So here is where we can actually set the map asset name on our load slot, which means our load slot

05:20.680 --> 05:23.230
needs the map asset name as a variable.

05:23.230 --> 05:27.310
So let's open up load slot I don't need the CP, I want the h file.

05:27.310 --> 05:31.900
So I can close the CP and add a new variable to load slot.

05:31.900 --> 05:33.610
I'm going to make it an F string.

05:34.710 --> 05:36.990
And call this map asset name.

05:38.270 --> 05:40.010
And give it a U property.

05:41.510 --> 05:46.760
And now in load screen when we're setting all the properties on load slot, when we first create a new

05:46.760 --> 05:49.220
slot, we can set the map asset name.

05:49.220 --> 05:51.140
And I'm going to do it right here.

05:51.140 --> 05:55.910
We're going to say load slots of slot I'm going to set map.

05:57.520 --> 05:58.720
Asset name.

05:59.350 --> 06:03.190
Now what is the map asset name going to be?

06:03.220 --> 06:05.950
Well, we have our aura game mode.

06:07.100 --> 06:14.780
And or a game mode has the default map as a t soft object pointer, and we can use two soft object path

06:14.780 --> 06:20.180
dot get asset name to get that asset name and we can save it there.

06:20.840 --> 06:30.800
So now load slots of this slot has that default asset name by default and or a game mode save slot data

06:30.800 --> 06:32.990
is responsible for saving that data.

06:32.990 --> 06:38.810
If we go to save slot data we'll see here that we're taking the load screen save game that's created

06:38.810 --> 06:39.410
here.

06:39.410 --> 06:41.000
And setting things here.

06:41.000 --> 06:49.880
Based on the slot we can set the map asset name, load screen save, game map, asset name, and we

06:49.880 --> 06:51.500
can get that load slot.

06:52.430 --> 06:52.940
Map.

06:52.940 --> 06:53.900
Asset name.

06:54.410 --> 06:55.730
Okay, that's all great.

06:55.760 --> 06:59.420
Now our game mode base has a function player died.

06:59.420 --> 07:02.540
And in this function we travel to a new level.

07:02.540 --> 07:06.530
We actually just travel to the map that we've saved already.

07:06.530 --> 07:13.400
And now we're sure to have a saved map asset name in our save game object, even when it's our first

07:13.400 --> 07:14.480
time playing.

07:14.480 --> 07:20.870
And thanks to our checkpoint now saving the map name, we always have a map name for when we save our

07:20.870 --> 07:22.100
game as well.

07:22.130 --> 07:25.280
Now we need a way to call player died.

07:25.280 --> 07:30.590
We should do this when the player dies and our combat interface has a die function.

07:30.590 --> 07:38.030
In fact, if we go to character and go to our character and go to its header file and take a look at

07:38.030 --> 07:42.320
its combat interface, it looks like we're not actually implementing that function.

07:42.320 --> 07:49.160
So I'm going to close all other tabs just or a character, and we're going to override that virtual

07:49.160 --> 07:51.710
die function from the combat interface.

07:51.710 --> 07:53.840
Virtual void die.

07:53.840 --> 07:59.600
And we'll notice that it's not just an empty function if we go to interaction.

08:00.410 --> 08:02.630
In the public folder of course.

08:02.630 --> 08:04.460
Combat interface dot h.

08:06.050 --> 08:07.610
And search for Dei.

08:07.640 --> 08:12.320
We'll see that it takes a const f vector for the death impulse.

08:12.410 --> 08:14.900
So we're going to want that function.

08:14.900 --> 08:16.490
We're going to override it.

08:16.580 --> 08:19.430
And we're going to provide a definition.

08:19.430 --> 08:26.660
And because the base character class does all sorts of things in die we're going to call super die passing

08:26.660 --> 08:28.010
in the death impulse.

08:28.850 --> 08:33.140
After that we're free to do with this function what we wish.

08:33.140 --> 08:40.190
And by the way, if you forget what the base class does in die, you can go to or a character based

08:40.190 --> 08:42.320
CPP and you can look at die.

08:42.320 --> 08:48.290
We basically call multicast handle death after detaching the weapon, and in multicast handle death

08:48.290 --> 08:53.930
we do all kinds of things, including adding impulses, set simulate physics.

08:53.930 --> 08:58.850
That's why we're actually ragdolling deactivating, burn and debuff components.

08:58.850 --> 09:02.600
Setting be dead to true all sorts of things.

09:02.600 --> 09:04.910
We're even broadcasting it on death delegate.

09:04.910 --> 09:10.070
So this is all stuff that we definitely want to do right now in our character.

09:10.070 --> 09:14.960
When we die, we want to call that function, but I don't want to call it right away.

09:14.960 --> 09:19.040
I want to do this after a few seconds of lying there.

09:19.040 --> 09:24.230
This gives us time to show any effects, to show a message.

09:24.230 --> 09:29.300
If you want to say you died something like that, maybe explain that you'll go back to your previous

09:29.300 --> 09:31.790
checkpoint, anything you wish.

09:31.790 --> 09:38.120
So for that reason, I'd like a death timer and we'll put this right under the combat interface.

09:38.120 --> 09:42.590
I'm going to have actually a float called Death Time.

09:43.390 --> 09:45.250
We'll set it to five seconds.

09:45.250 --> 09:46.780
So five dot f.

09:46.780 --> 09:52.120
And of course this is something you should set with edit defaults only.

09:53.020 --> 09:55.120
And I'm also going to have a timer.

09:55.120 --> 09:56.830
Now to set a timer from C plus.

09:56.830 --> 10:01.540
Plus we use it F timer handle just like we've used them in blueprint.

10:01.540 --> 10:03.730
And we're going to call this death timer.

10:03.730 --> 10:09.310
And in or a character die I want to set that timer.

10:09.310 --> 10:15.520
Now to set the timer we'll either need a callback or we could use an f timer delegate.

10:15.520 --> 10:19.420
If I make an f timer delegate called timer delegate.

10:20.890 --> 10:23.350
More specifically death timer delegate.

10:23.350 --> 10:25.720
We can bind a callback to it.

10:25.750 --> 10:27.280
We could bind a lambda to it.

10:27.280 --> 10:35.710
I'm going to take timer, delegate, and bind a lambda, and the lambda is going to capture this, but

10:35.710 --> 10:37.510
it takes zero inputs.

10:38.530 --> 10:40.420
So this is our delegate.

10:40.420 --> 10:42.250
And what am I going to do here?

10:42.250 --> 10:48.430
Well, in the delegate I'd like to get the aura game mode base, a aura game mode base.

10:48.430 --> 10:50.770
We'll call it aura GM.

10:50.980 --> 10:54.880
We'll cast to a aura game mode base.

10:54.880 --> 11:03.520
The result of you gameplay statics get game mode, which requires a world context object passing in

11:03.520 --> 11:05.470
this and we'll say if.

11:06.370 --> 11:15.520
Or a GM then or a GM player died and we'll pass in this.

11:17.570 --> 11:20.300
As this is the player that's dying.

11:20.300 --> 11:23.120
So we've bound this lambda to this delegate.

11:23.120 --> 11:25.640
Now we can just set this timer.

11:25.640 --> 11:28.880
And we do that with get world timer manager.

11:29.360 --> 11:31.100
We get the world timer manager.

11:31.100 --> 11:32.750
We call set timer on it.

11:32.750 --> 11:35.450
We pass in the timer handle.

11:35.450 --> 11:39.320
So death timer we pass in the delegate next.

11:39.320 --> 11:44.120
So death timer delegate we pass in the time.

11:44.120 --> 11:45.470
So death time.

11:45.830 --> 11:50.600
And if we want to loop or not false would say no don't loop.

11:50.990 --> 11:52.220
And that's it.

11:52.250 --> 11:58.880
Now you may have noticed, as you may have been playtesting, that every once in a while you'll die

11:58.880 --> 12:01.130
and the camera will just fall.

12:01.490 --> 12:08.630
We can easily prevent that by taking our top down camera component and calling detach from component,

12:08.630 --> 12:13.490
and this requires an EF detachment transform rules.

12:13.490 --> 12:16.100
And I'm going to choose Keep World transform.

12:16.100 --> 12:17.870
We want to keep that world transform.

12:17.870 --> 12:20.840
But we don't want our camera to just fall.

12:20.840 --> 12:24.380
So with that we now have something happening.

12:24.380 --> 12:27.320
When aura dies, we can test that out.

12:27.320 --> 12:29.780
We can compile and play.

12:30.490 --> 12:33.100
Okay, so now we can test out death.

12:33.100 --> 12:40.990
Now what I'm going to do is go into blueprints, ability, system data, CT damage, and up my first

12:40.990 --> 12:44.260
level melee damage to 100.

12:44.260 --> 12:47.620
This will just help me test death for now.

12:47.620 --> 12:51.280
Okay, so after setting that damage, we can test the game.

12:51.280 --> 12:54.700
Now if we don't have a valid save game object, nothing will happen.

12:54.700 --> 12:59.020
So we're going to have to load in through the load menu.

12:59.020 --> 13:05.950
And again I'm just going to delete that slot, make a new one and play test death.

13:09.300 --> 13:09.780
Okay.

13:09.780 --> 13:13.740
There's death happening five seconds later, I expect.

13:13.770 --> 13:14.820
There we go.

13:14.820 --> 13:15.570
We went back.

13:15.570 --> 13:17.760
Now let's see if we can save our progress.

13:17.760 --> 13:19.500
I'm going to reach a beacon.

13:19.500 --> 13:26.550
I'm going to reach this checkpoint here, and then I'm going to die and see if we respawn back at that

13:26.550 --> 13:27.510
checkpoint.

13:28.900 --> 13:33.670
So five seconds to go and then back at the checkpoint.

13:33.670 --> 13:36.520
The beacon and the checkpoint are reached.

13:37.400 --> 13:37.970
Okay.

13:37.970 --> 13:38.810
Perfect.

13:38.960 --> 13:45.860
Now, one thing I've noticed when dying, and you probably noticed this in testing, is when aura ragdolls

13:45.860 --> 13:48.350
she's actually still in the idle animation.

13:48.350 --> 13:51.230
The hips are kind of still animating a little bit.

13:51.230 --> 13:57.650
It's really hard to tell, but if you look closely enough, it's happening so we can fix that pretty

13:57.650 --> 14:06.680
easily by going to Character Aura, ABP aura, and in ABP aura, we can make sure that we don't do anything

14:06.680 --> 14:07.580
if dead.

14:08.480 --> 14:12.770
So let's take a look at our character.

14:13.430 --> 14:22.190
And in fact this might be or a character base it is or a character base has a be dead variable.

14:22.190 --> 14:23.540
Let's find it.

14:25.180 --> 14:25.990
Be dead.

14:25.990 --> 14:30.850
It's not exposed and it's not replicated, but it's set in multicast handle death.

14:30.850 --> 14:33.220
So it is set on clients as well.

14:33.220 --> 14:37.780
We just can't see it in the blueprint editor in the event graph.

14:37.780 --> 14:40.000
So we're going to make this blueprint read only.

14:40.240 --> 14:44.020
So that way we can access it from the Animation blueprint.

14:44.020 --> 14:46.600
So I'm going to go ahead and close down and restart.

14:46.600 --> 14:49.210
And it's not that we need a death pose per se.

14:49.240 --> 14:56.320
We just don't want to be playing any animations while dead because ragdoll is taking care of that for

14:56.320 --> 14:57.010
us.

14:57.010 --> 14:58.840
Okay, so we're back.

14:58.870 --> 15:06.400
I'm back in ABP Ora, I'm in the event graph, and I'm going to have one more part here where I get

15:06.430 --> 15:09.760
BP or a character, I'm going to get dead.

15:11.990 --> 15:14.120
Sounds like I'm dying, right?

15:14.120 --> 15:15.110
Going to get dead.

15:15.110 --> 15:20.720
And I'm going to promote this to a variable called dead and hook that up here.

15:20.720 --> 15:29.960
Now we have dead, we can go into our main states, and what we'll do is we'll just do a new state here

15:29.960 --> 15:30.950
called dead.

15:30.950 --> 15:37.730
I'm not going to put any animations into it, and I'm going to use a state alias called Two Dead.

15:38.880 --> 15:40.530
That'll go straight to dead.

15:40.530 --> 15:45.750
And I want to go straight to dead from all the other states, if dead is true.

15:45.870 --> 15:51.750
So I can take two dead and I can check all of these states.

15:51.750 --> 15:57.780
And if we're in any of them, we'll go to dead, except perhaps in air.

15:57.780 --> 16:02.250
If we die well, in the air, we might want to go back to idle first.

16:02.250 --> 16:05.700
So that might be the only exception.

16:06.540 --> 16:08.640
But then again, if we're ragdolled, it doesn't matter.

16:08.640 --> 16:10.440
So I'm just going to have all the states.

16:10.440 --> 16:12.240
And with that.

16:12.800 --> 16:16.850
That will prevent any poses from being played if dead.

16:16.880 --> 16:22.730
Okay, so we have death and really we can do anything we want on death.

16:22.730 --> 16:28.970
You can subtract some experience, but then you'd have to of course recalculate and see how you'd have

16:28.970 --> 16:35.330
to handle demoting a player to a lesser level if there's a level change.

16:35.330 --> 16:44.060
So that is a whole separate area if you want to get into doing things in response to death.

16:44.060 --> 16:50.900
And it involves skills that you have things that you can do, there's nothing you can't do by the way

16:50.900 --> 16:54.140
of subtracting or taking away things.

16:54.140 --> 16:55.130
When you die.

16:55.130 --> 17:00.860
You just have to take into account that you may have a reverse level up.

17:00.890 --> 17:05.930
Of course, you could treat that as a level up with a negative value if you like.

17:05.930 --> 17:08.960
But again, there's a list of challenges there.

17:08.960 --> 17:11.180
But other than that, we now have death.

17:11.180 --> 17:13.370
We now have a way to die.

17:13.940 --> 17:22.190
And another thing you can do is you can dissolve aura just like you dissolve the other enemies when

17:22.190 --> 17:23.000
you kill them.

17:23.000 --> 17:26.060
So that's something you could think about doing as well.

17:26.060 --> 17:31.640
Now, if you're sitting here waiting for a respawn and you're not getting it, you may want to double

17:31.640 --> 17:34.880
check that you actually load it in through the menu.

17:34.880 --> 17:37.760
Otherwise there is no save game object for you.

17:37.760 --> 17:41.090
So just something to keep in mind.

17:41.090 --> 17:46.490
Load in through your save game object if you expect that death to work at all.

17:46.490 --> 17:51.950
And if you don't want to be confused in the case where you don't have a save game object, maybe print

17:51.950 --> 17:57.440
a debug message to the screen and say hey, you don't have a save game object, you might want to load

17:57.440 --> 17:58.460
in through the menu.

17:59.660 --> 18:01.430
All right, excellent job.

18:01.430 --> 18:02.960
Aura now dies.

18:02.960 --> 18:05.660
We can respawn at our last checkpoint.

18:05.660 --> 18:08.150
It's acting more like a real game now.

18:08.150 --> 18:10.550
Excellent job, and I'll see you soon.
