Welcome back.
Now we're almost complete with all of the main mechanics of this game project, except for when aura
dies.
When aura dies, she ragdolls, sure, but that's it.
And from that point on, aura is just laying on the floor and you have to hard exit the game, right?
So what we're going to do is determine what happens when aura dies.
And I'm fine with just a simple timer.
Wait for a few seconds and then respawn at the last checkpoint or the beginning of the game if there
is no checkpoint saved.
So this is perhaps going to start in the game mode.
I'm going to open Aura Game Mode base, and we're going to make a new function here for when a player
dies.
So this will be a void function.
And I'm going to call this player died.
It's going to be public.
And I'm going to pass in an A character just in case we want something to do with that dead character.
This is really for the future.
I don't really have much I want to do with the dead character, other than just have it in case we want
it.
Now, if the player dies, I want to first of all, load up our save game object and see what our map
is that we last saved our progress at.
Which means I need a you load screen save game.
I'll call this save game and I'll retrieve end game.
Save data and recall what this function does for us.
Retrieve end game.
Save data.
Gets the game instance, gets the load slot, name and index from it, and simply gets save slot data
with that name and index and get save slot data is just going to load a game from slot if it exists.
Otherwise it'll create a new one, cast it to a load screen, save game and return it.
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
and basically return if it's not.
So if not is valid.
Save game, we can return.
And after that we can simply travel to the level that's in that save game.
Now we can do this with you.
Gameplay statics.
Open level and open level first requires a world context object.
How convenient.
We have the dead character and we can convert the map asset name to an F name.
As this does require an F name, we can get our save game object.
And get the map asset name and we can travel to it now.
Dead character is an A character.
We have to include the character type.
Our game mode thus far has not used anything of the sort, so we need to use game framework character
dot h if that is to be a defined type.
Okay, now this is great.
The game mode has a way to travel us to the level saved in that save game object.
But the problem is this is the map asset name.
And we're not actually saving that in all cases.
In fact, the only time we're setting this is from our map entrance.
If we go to the checkpoint folder into map entrance dot cp, we'll see that we're calling the save world
state function, passing in an asset name for the map.
But this is only for when we're traveling to a new map.
If we save at a checkpoint, we're actually passing in nothing for that second parameter, which means
no map name will be saved.
So it's kind of important that we save that map name.
I think we should do that in the checkpoint dot CP.
As we're saving the world state, we should save the name of the current level, which we can always
get because we can get the world.
We can make a const you world pointer and initialize it with get world, and we can get its name.
We can make an f string called map name, and we can use the world which I didn't give a name.
I'm going to call it world.
We can use this world and call get map name.
Of course it has the streaming levels prefix, so we have to take map name and call remove from start
world streaming levels prefix.
And now we have the asset name which we can pass in.
So we can pass in map name here.
Now that's great.
But there's also another thing that we have to realize.
We have to realize that when we create a new game, we're not really initializing the map asset name.
We're not saving anything to our save game object at that point.
So we need to save the map asset name.
We have to save it when we create a new slot.
So we can go to ViewModel load screen and new slot button pressed.
Here is where we are setting properties on our slot that we're going to save in our save game object,
because we're passing in to our Or game mode, that slot when we call save slot data.
So here is where we can actually set the map asset name on our load slot, which means our load slot
needs the map asset name as a variable.
So let's open up load slot I don't need the CP, I want the h file.
So I can close the CP and add a new variable to load slot.
I'm going to make it an F string.
And call this map asset name.
And give it a U property.
And now in load screen when we're setting all the properties on load slot, when we first create a new
slot, we can set the map asset name.
And I'm going to do it right here.
We're going to say load slots of slot I'm going to set map.
Asset name.
Now what is the map asset name going to be?
Well, we have our aura game mode.
And or a game mode has the default map as a t soft object pointer, and we can use two soft object path
dot get asset name to get that asset name and we can save it there.
So now load slots of this slot has that default asset name by default and or a game mode save slot data
is responsible for saving that data.
If we go to save slot data we'll see here that we're taking the load screen save game that's created
here.
And setting things here.
Based on the slot we can set the map asset name, load screen save, game map, asset name, and we
can get that load slot.
Map.
Asset name.
Okay, that's all great.
Now our game mode base has a function player died.
And in this function we travel to a new level.
We actually just travel to the map that we've saved already.
And now we're sure to have a saved map asset name in our save game object, even when it's our first
time playing.
And thanks to our checkpoint now saving the map name, we always have a map name for when we save our
game as well.
Now we need a way to call player died.
We should do this when the player dies and our combat interface has a die function.
In fact, if we go to character and go to our character and go to its header file and take a look at
its combat interface, it looks like we're not actually implementing that function.
So I'm going to close all other tabs just or a character, and we're going to override that virtual
die function from the combat interface.
Virtual void die.
And we'll notice that it's not just an empty function if we go to interaction.
In the public folder of course.
Combat interface dot h.
And search for Dei.
We'll see that it takes a const f vector for the death impulse.
So we're going to want that function.
We're going to override it.
And we're going to provide a definition.
And because the base character class does all sorts of things in die we're going to call super die passing
in the death impulse.
After that we're free to do with this function what we wish.
And by the way, if you forget what the base class does in die, you can go to or a character based
CPP and you can look at die.
We basically call multicast handle death after detaching the weapon, and in multicast handle death
we do all kinds of things, including adding impulses, set simulate physics.
That's why we're actually ragdolling deactivating, burn and debuff components.
Setting be dead to true all sorts of things.
We're even broadcasting it on death delegate.
So this is all stuff that we definitely want to do right now in our character.
When we die, we want to call that function, but I don't want to call it right away.
I want to do this after a few seconds of lying there.
This gives us time to show any effects, to show a message.
If you want to say you died something like that, maybe explain that you'll go back to your previous
checkpoint, anything you wish.
So for that reason, I'd like a death timer and we'll put this right under the combat interface.
I'm going to have actually a float called Death Time.
We'll set it to five seconds.
So five dot f.
And of course this is something you should set with edit defaults only.
And I'm also going to have a timer.
Now to set a timer from C plus.
Plus we use it F timer handle just like we've used them in blueprint.
And we're going to call this death timer.
And in or a character die I want to set that timer.
Now to set the timer we'll either need a callback or we could use an f timer delegate.
If I make an f timer delegate called timer delegate.
More specifically death timer delegate.
We can bind a callback to it.
We could bind a lambda to it.
I'm going to take timer, delegate, and bind a lambda, and the lambda is going to capture this, but
it takes zero inputs.
So this is our delegate.
And what am I going to do here?
Well, in the delegate I'd like to get the aura game mode base, a aura game mode base.
We'll call it aura GM.
We'll cast to a aura game mode base.
The result of you gameplay statics get game mode, which requires a world context object passing in
this and we'll say if.
Or a GM then or a GM player died and we'll pass in this.
As this is the player that's dying.
So we've bound this lambda to this delegate.
Now we can just set this timer.
And we do that with get world timer manager.
We get the world timer manager.
We call set timer on it.
We pass in the timer handle.
So death timer we pass in the delegate next.
So death timer delegate we pass in the time.
So death time.
And if we want to loop or not false would say no don't loop.
And that's it.
Now you may have noticed, as you may have been playtesting, that every once in a while you'll die
and the camera will just fall.
We can easily prevent that by taking our top down camera component and calling detach from component,
and this requires an EF detachment transform rules.
And I'm going to choose Keep World transform.
We want to keep that world transform.
But we don't want our camera to just fall.
So with that we now have something happening.
When aura dies, we can test that out.
We can compile and play.
Okay, so now we can test out death.
Now what I'm going to do is go into blueprints, ability, system data, CT damage, and up my first
level melee damage to 100.
This will just help me test death for now.
Okay, so after setting that damage, we can test the game.
Now if we don't have a valid save game object, nothing will happen.
So we're going to have to load in through the load menu.
And again I'm just going to delete that slot, make a new one and play test death.
Okay.
There's death happening five seconds later, I expect.
There we go.
We went back.
Now let's see if we can save our progress.
I'm going to reach a beacon.
I'm going to reach this checkpoint here, and then I'm going to die and see if we respawn back at that
checkpoint.
So five seconds to go and then back at the checkpoint.
The beacon and the checkpoint are reached.
Okay.
Perfect.
Now, one thing I've noticed when dying, and you probably noticed this in testing, is when aura ragdolls
she's actually still in the idle animation.
The hips are kind of still animating a little bit.
It's really hard to tell, but if you look closely enough, it's happening so we can fix that pretty
easily by going to Character Aura, ABP aura, and in ABP aura, we can make sure that we don't do anything
if dead.
So let's take a look at our character.
And in fact this might be or a character base it is or a character base has a be dead variable.
Let's find it.
Be dead.
It's not exposed and it's not replicated, but it's set in multicast handle death.
So it is set on clients as well.
We just can't see it in the blueprint editor in the event graph.
So we're going to make this blueprint read only.
So that way we can access it from the Animation blueprint.
So I'm going to go ahead and close down and restart.
And it's not that we need a death pose per se.
We just don't want to be playing any animations while dead because ragdoll is taking care of that for
us.
Okay, so we're back.
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
BP or a character, I'm going to get dead.
Sounds like I'm dying, right?
Going to get dead.
And I'm going to promote this to a variable called dead and hook that up here.
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
called dead.
I'm not going to put any animations into it, and I'm going to use a state alias called Two Dead.
That'll go straight to dead.
And I want to go straight to dead from all the other states, if dead is true.
So I can take two dead and I can check all of these states.
And if we're in any of them, we'll go to dead, except perhaps in air.
If we die well, in the air, we might want to go back to idle first.
So that might be the only exception.
But then again, if we're ragdolled, it doesn't matter.
So I'm just going to have all the states.
And with that.
That will prevent any poses from being played if dead.
Okay, so we have death and really we can do anything we want on death.
You can subtract some experience, but then you'd have to of course recalculate and see how you'd have
to handle demoting a player to a lesser level if there's a level change.
So that is a whole separate area if you want to get into doing things in response to death.
And it involves skills that you have things that you can do, there's nothing you can't do by the way
of subtracting or taking away things.
When you die.
You just have to take into account that you may have a reverse level up.
Of course, you could treat that as a level up with a negative value if you like.
But again, there's a list of challenges there.
But other than that, we now have death.
We now have a way to die.
And another thing you can do is you can dissolve aura just like you dissolve the other enemies when
you kill them.
So that's something you could think about doing as well.
Now, if you're sitting here waiting for a respawn and you're not getting it, you may want to double
check that you actually load it in through the menu.
Otherwise there is no save game object for you.
So just something to keep in mind.
Load in through your save game object if you expect that death to work at all.
And if you don't want to be confused in the case where you don't have a save game object, maybe print
a debug message to the screen and say hey, you don't have a save game object, you might want to load
in through the menu.
All right, excellent job.
Aura now dies.
We can respawn at our last checkpoint.
It's acting more like a real game now.
Excellent job, and I'll see you soon.