Currently trying out some multiplayer stuff in Unreal Engine 4 and was wondering how I was going to add hitboxes to the controlled characters, since I have been so lazy at writing in my blog lately I thought I might write up a tutorial on the subject. 🙂
Hitboxes
I started first of with thinking about the different damage distribution. I concluded that I wanted 3 different types of hitboxes. One for headshot, I must have a headshot. 🙂 One for bodyshot and one for limbs.
This is how I considered my hitboxes and the damage they give.
- Headshot (100 damage, instant death)
- Bodyshot (25 damage, 4 hits death)
- Limbshot (10 damage, 10 hits death)
This can off course be modified later with things such as damage over distance, adding armor that gives extra hp and so on, lets get to the basics of it first.
How to set up the hitboxes
The way I figured out to do it was to take collision capsule or a box and attach it to the socket. In this case, it is the head shot capsule we are attaching. I am going to attach it to the head socket. Set everything to 0. Then start scaling, moving, rotating it to fit the head better. I tried to name so that I could use the names later to determine if it was a body shot or, limb shot or a head shot.
I changed the color of the character so it was possible to see the hit boxes a little better.
Collision
We need some specific collision for our hitboxes. The thing is, when a bullet hits, we want the bullet to ignore our capsule, it needs to fly trough the capsule and hit our hitbox. If it is stopped by the capsule, the hit wont register when we create the damage later. This is demonstrated in the image to the right.
In my project settings in UE4 there is a section called “Collision”. I made two new object channels.
- HitBoxes
- Bullets
I put their default response to ignore. I then set the “block all” and “block all dynamic” profile to block the bullets (or else the bullets wont be stopped by a wall, or the ground).
Under preset, I made two new profiles. One for Bullets and one for Hitboxes. In the bullets section I made it ignore all except hitboxes, destructible (might want that later if I want to shoot a wall up), world static (the bullet needs to register a hit when it hits a wall or the ground) and world dynamic.
In the Hitboxes profile I made it ignore all except bullets and visibility (the reason I want it to register visibility is because I later have to calculate where the character aims ). Next thing we have to do is to set the characters hitboxes to the hitbox collision profile we made. Also set CollisionEnabled to “Query Only” on both the profiles we just made.
Now our collision should be all set.
The projectile
Now that our character is all set to be fired upon, we need to go the projectile. I am not going to cover how to fire the projectile or how to make the projectile. There are plenty of tutorials on that subject. I will even link to one above so you can figure that out.
The important thing is that the projectile has a collision that is set to the bullet profile we made in our collision. This is very important so that we know it will register right. It can get a little confusing with collision at times but after a little practice you will get used to it. On the mesh for the bullet I justs set the collision to ignore everything.
On the collision you now have to get a OnComponent hit event. As shown in the image to the right. You then have to get the hit result.
Now in the end I have added a apply point damage. (The reason for point damage is that I wanted to calculate where hit came from and how far away the shot came from, I wont be dealing with that in this tutorial. Just important that you know why I choose that, but this also work with normal damage.)
Now from my hitresult I get the hit actor and hook it up to the damaged actor. This is very logical, the hit actor is the actor you want to damage.
We also need a float variable, call it “damage“. This is obviously how much damage this projectile is going to give when it hits. Hook it up to “base damage” on the “apply damage” node. We will later create two new functions. One of them will set the damage variable depending on what hitbox we hit. We also need to create an enum and fetch it into our projectile as a variable. In the enum I made 4 listing. Headshot, Bodyshot, Limbshot and Nothing. The last one, nothing is the default one. It was just something I made temporary for when my bullet hits a wall or something that is not a hitbox. I dont want to fire into a wall and get a limbshot or a headshot in the debug. 😛
Now we have to create two functions. The First one I have called “Set Hitbox hit“. This function will set the enum depending on whatever hitbox you hit. So what I did was to go to my hit result. Under “hit component” I got the object name. Plugged it into the function “Set Hitbox Hit“
Then in the “Set Hitbox hit” function I made this system. Is basicly fetches the string we got from our hitresult. Checks the prefix, and if the prefix is Body, Limb or Head, it will set the enum to the correct one. I also added a print string on the end to debug what I hit, so that I know when I shoot in the body, it hits the body hitbox.
The second function I called “set damage given”. It sets the damage depending on what you hit. Like I said earlier you can set it to whatever you want, but as I mentioned, I set it to Headshot (100 damage, instant deathm, Bodyshot (25 damage, 4 hits death, Limbshot (10 damage, 10 hits death).
This does it for our projectile, now we need the character to receive the damage.
Character take damage
What we were missing, and the last step of this tutorial, is to to give the damage to the character.
We go back to the characters blueprint. Create two variables to define our health. First we need a float variable called health, set it to 100. Then create another float variable called maxhealth and set it to 100
Now that our health is set up we need to create an “Event Point Damage“. We also must create a new function that is called “deal taken damage“. It should have several inputs, but the most important one is the damage. You can ignore the two others for now.
“Damage causer” is what projectile caused the damage, and “instigated by” is who caused the damage (the owner of the projectile).
In the function “deal taken damage” I have set damage to a local variable. I have also made a variable called “is dead”, because I have a death animation when character hits 0 health. This is not important if we are just focusing on the hitboxes. The important thing is that you can shoot the hitboxes and lose health accordingly.
So health subtracts the local damage with a clamp on it. We don’t want to lose below 0 in health and we don’t want to gain more health than max health. Also you notice that my health is rep-notify. I am currently making a network game, so in my rep-notify function I just have branch that checks if I the character has 0 in health or below, if that is true the character plays death animation. You might want to add a print string after the health to check if the character loses the right amount of health and so on.
Testing and conclusion
I shot the character in the body, it loses 25 health. The print string informs me that I hit the Body (from the enum in the projectile).The other print string informs me the amount of health that is left.
Same here. I shot the character in the limb (the right arm), and the character lost 10 health. (enum print string tells me its a limbshot.)
I finish off the character with a shot to the head, it loses the rest of it’s health. (enum print string informs me I hit the head).
It worked just as I hoped. I mean, it is not really that complex. 🙂