This is the first post in a series about Ataraxy, a roguelike platform brawler.
This content is the inspiration for creation of this series, so I will give some background on the project.
I had free time over Winter break between Graduate Semesters, so I decided to throw myself at a side project – a roguelike platform brawler.
The game world is made up of procedurally generated floating islands. You encounter enemies, gaining weapons and tools. You fight enemies that level up as you fight them, which creates natural pacing (Which I’ll no doubt discuss in a future post). Weapons fall into two general categories – ranged weapons and melee weapons. This is an in-depth description.
Common Approach to Melee weapons
A number of games (Team Fortress 2, Half Life) approach melee weapons by using hitscan – performing a single raycast or collision line forward. If this raycast hits an enemy, it deals damage or applies some other effect. This is usually the way games calculate instant velocity bullets. The difference between instant velocity bullet weapons and melee hitscan weapons is the latter usually has a short max distance before it stops checking.
This is not an ideal approach for a number of reasons. Consider a virtual axe, which has a shaft and a blade. If you were to swing the axe in TF2, you only have a boolean outcome for hitting or missing. This doesn’t allow you to consider if the player hit with the axe, the shaft or missed entirely.
I wanted a better approach than this.
I took a page out of Realm of the Mad God’s book. In that game, all of the enemies fire swaths of projectiles. Their implementation for melee weapons was a short-ranged projectile like a sword, dagger or club.
[embedyt]https://www.youtube.com/watch?v=9eIv1lk5Yzk[/embedyt]
Note the short range of this player’s attacks.
I mirrored this approach and I created a short-lived melee projectile, which I’ll call a slash.
I knew a slash would need a few points to render with. I have ‘firing points’ from around the player for different weapon starting positions – rocket launcher goes on the shoulder, machine gun goes at the waist, sword slashes are sideways, etc.
I created a box collider trigger volume (a standard way of handling projectiles in Unity). I gave it a non-gravity affected rigidbody and a decent amount of drag so it wouldn’t travel very far.
Orienting the Collider
I oriented the box collider with the slash’s end points by using the two end points and the forward direction of the slash to find the up vector.
Within my Weapon base class, I have a method for setting up a melee projectile. It currently looks like this:
This is set up so child weapons could replace this method if necessary. However, I made it generic enough that I haven’t had to replace it after implementing 4 different melee weapons. In order to use a weapon, you need to call the child’s UseWeapon function. This takes in target and fire point information. Each individual weapon’s version of UseWeapon handles differently and will until I can generalize further. Inside of the melee weapons, they configure the linePoints, lineWidth and specialVelocity if necessary while passing along certain information like the direction the projectile will move in.
In order to orient the Collider upwards, first we take the cross product of the two ends of our weapon strike. This gives us the direction of what is perpendicular to our line.
We then use Unity’s transform.LookAt() method to rotate the collider to orient it in the direction we’re firing. We use the the perpendicular direction to state what the projectile should consider to be ‘Up’. This results in tilting the collider to match the tilt of the two end points.
There is a final call to a method for Adjusting the projectile’s collider position. This usually means slightly moving the collider forward or backward to match the particular weapon’s visual component.
What is even better about the use of a special method for orienting the collider is that it could be overloaded in subclass weapons without changing SetMeleeProjectile.
Lastly, I set the alpha on the slash’s line renderer to fade over time (which aligns with the destruction of the melee projectile)
Closing Words
Alternatives
There are a great number of ways to solve this issue.
A common enough approach is the idea of a continuous hitscan, performing multiple hitscan checks to determine how long the target is hit and in what regions.
Multiple mini-projectiles can be used to see if an enemy is hit by different phases of a sword swing.
A rotational multi-projectile could model the different ways an enemy could be hit by a swinging blade (with a lower damage handle and a grazing tip)
These different approaches are usually fairly expensive and require deeper implementations.
Pros and Cons
The result of my current solution is a single projectile instantiation, box collider trigger, tag checks, a bit of vector math for rotation and finally rigidbody calculations. This approach can even be improved to suit multiple projectile creation in a particular formation as well as shape changing projectiles.
Thank you for reading, happy implementing!