Welcome back.
We now have a hit React and that's a gameplay ability.
I'd now like to implement death for when an enemy has its health reduced down to zero.
In other words, here in the attributes set when be fatal is true, we want to call some sort of function
for the character to die.
Now, death is something that ora and enemies should share.
So I'd like to add a function to the combat interface.
So I'm going to go ahead and close all tabs for now and open the interaction folder and get my combat
interface open here.
And I'm going to declare a new function here.
It's going to be a virtual function void, and I'm going to call it Die.
I'll go ahead and make it a pure virtual function so that it has to be implemented and we'll first implement
this in our character base.
So I'm going to go into the character folder and open or a character base and all the way up at the
top, I'm going to override it here.
Virtual void die override, and we can handle what happens here.
Now, in Die, I'd like to drop the weapon.
That's something we can do in Die.
But I'd also like to ragdoll the enemy.
This allows us to get away with not really needing to play a death montage.
We know how to play montages.
In fact, we could just make a death gameplay ability that does pretty much the same thing that our
hit React does.
But for death, I'm going to decide to implement this differently.
I'd like to ragdoll the enemy instead.
Now, if we ragdoll the enemy, we're going to need to do things on the server and on the client.
So for that reason I'm going to create a multicast RPC.
So this function is going to also be a virtual function.
Virtual void.
And I'm going to call this multicast handle death.
So we can override this in child classes if we want to do things in child classes specifically.
But this is going to be what we use to handle what happens on all clients whenever a character dies.
Now this needs to be a new function.
If we're going to make this a multicast RPC, we need to add net multicast to the function and specify
whether it should be reliable or unreliable.
I think death should be reliable.
Now I'm going to implement this function and when I generate the definition, writer is going to make
the definition have implementation that's required for the multicast RPC.
It has to have that implementation there so we can handle what happens on all machines, client and
server in the multicast handle death implementation and then the die function can handle what happens
specifically on the server and then we'll only call die on the server.
So the die function is going to call multicast handle death so we can put that there.
And before we call multicast handle death, we can detach the weapon.
I'd like to drop the weapon so we can take that weapon variable and call detach from component.
And this requires f detachment transform rules so we can make one f detachment transform rules and the
F detachment transform rules.
Struct has a constructor that requires an E detachment rule.
I'm going to pass one in so E detachment rule I'm going to use keep world.
So the weapon can keep the world transform and we have a bool be in call modify that we can pass in
true for.
So this will result in detaching the weapon and that detachment is something that will automatically
be a replicated action.
So if we detach on the server, we don't have to detach on clients.
But there are a number of things I want to do that we can't just do on the server we have to do on the
server and clients.
That's why we're calling multicast handle death and in multicast handle death.
This is where I'd like to ragdoll the character.
In other words, simulate physics for the character and the weapon for that matter.
So in multicast, handle death, we're going to take the weapon.
We're going to call, set, simulate physics passing in.
True.
And I'm going to enable gravity.
So we're going to call, set, enable gravity passing in.
True, making sure that that weapon drops.
Now, we can also enable collision for the weapon as it's not going to have collision.
We've set that to no collision by default.
But now we can set collision enabled and we can pass in collision enabled.
And we can choose physics only as we don't really care about any spatial queries, no overlap events,
anything like that.
We just want physics.
Now our weapon provided that it has a physics asset.
If it's a skeletal mesh, which it is, we'll bounce around on the ground.
And that's the effect I'm going for.
Now I'd like to ragdoll the mesh as well, which means I'm going to need to call, get mesh and enable
gravity on the mesh so we can call, set, enable gravity.
We can enable physics as well.
So get mesh.
Set simulate physics passing in.
True.
And just to be consistent.
I'm going to call, set, simulate physics first, just like I did up here with the weapon.
It doesn't matter which order we call these in.
And what I'd like to do is get the capsule and disable collision for the capsule.
So I'm going to call get capsule component and call set collision enabled.
Passing in.
Collision enabled.
No collision.
So that way the capsule will not be blocking other characters or other objects from passing through
it.
Now, in addition to this, I'd like to use set collision enabled passing in physics only for the mesh
as well.
So we'll do all the things we want to do to the mesh first before messing with the capsule.
So after set enabled gravity, we'll call, get mesh and call set collision enabled using physics only.
So we'll go ahead and do that as the mesh has no collision by default, just like the weapon.
And I'd like to set the collision response to the world static channel for the mesh to block.
So we're going to call get mesh, set, collision response to channel and we'll use EC world static
as that's going to be the walls and the floors and things like that.
We're going to set the response to block and then later, if we wish to implement some kind of impulse,
then we can fling the body in a specific direction.
So that's something we can think about doing later.
But for now, we're just ragdolling the enemy.
So now we have this nice interface function, Di and it's implemented here in Aura Character base.
We can override it to get additional behavior in child classes such as Aura Enemy, for example.
And I'd like to do that as well.
I'm going to copy virtual void die override from the character base and go into Aura Enemy.
And here for the combat interface, I'm going to override die.
We're going to generate the definition for it.
We do want to call super Die.
There's lots of good stuff happening there.
But for the enemy, I'd like to set its lifespan.
So we're going to call set lifespan and we can set the lifespan to some value, say five seconds, or
we can make this a parameter on the enemy and set it to that, since parameters in general are better,
let's just really quickly add a parameter.
We'll copy base, walk speed and we'll create a float called Lifespan.
We'll set it to five by default and I'd like this to be edit anywhere.
And we'll leave it at Blueprint read only it can be in category combat.
That's fine.
And we'll use this here in Die.
So we're going to set the lifespan and then call super die, which will result in the ragdolling.
Okay.
I'm going to compile really quick just to make sure there aren't any compiler errors that I may have
missed.
And it looks like we're good.
So now we have an interface function that we can use, and I'd like to use this in my attribute set.
So I'm going to go into Ora attribute set dot CPP.
And here we know if the damage caused was fatal.
If it is fatal, then we can easily call that interface function.
Now let's take a look at our props struct.
It's called f effect properties.
Now we didn't bother adding a pointer to the interface, the combat interface.
That's fine.
We can call this function if the target actor implements the interface.
So here's what I'll do is I'll say if be fatal.
And then we'll have an else case.
And then this stuff that was in the if not be fatal that can go just in the else case.
And then we don't have to check if not be fatal, we can just check if be fatal.
Then here we're fatal.
Otherwise we're hit reacting.
And if we're fatal, we can get the target actor from props.
Props Dot, Target, Avatar actor.
And we can see if it implements the interface.
So we can say I combat interface.
Combat interface equals cast to AI.
Combat interface.
And we'll cast props.
Target.
Avatar.
Actor.
And if the thing being damaged is a combat interface, we can call combat interface die just like that.
And then once damage is fatal, we should see the character ragdoll.
So now we can compile and test this out.
But our firebolt has ability level one, so it's only doing five damage.
We can up the amount of damage we're doing so we can test death a little easier by going to abilities
or a projectile spell.
And instead of passing in the ability level again, we can pass in a higher value for our scaled damage.
Why don't we pass in a value of, say, ten and that way we'll have a higher value for damage and we
can get to that death a lot easier.
So let's compile and launch this and see if we can trigger that death function.
Okay, we're back in the editor.
I'm going to click open, although I don't think I need any of these assets.
All I really want to do is test out death.
So I'm going to launch a fireball, do some damage, and let's see if we can get this guy down to zero
Health.
One more should do it.
And they ragdoll Look at that.
And of course we set the lifespan to five seconds as well.
So that's another cool thing that we're doing.
We see that they're dropping the weapon as well.
So this is looking pretty nice.
Okay, so we now have a death mechanic working and of course we have a few more things we're going to
want to implement.
Of course we're going to want to gain experience points.
When something dies, we're going to get to all those important RPG mechanics.
But in the meantime, we'll take care of showing a few more really cool cosmetic effects, such as dissolving
the character away.
And we'll get to those things in the videos to come.
So excellent job and I'll see you soon.