[System Design] Hit Detection

We did look into using ccd, but it looks like its for simulated rigid bodies. We did also think about making the collision way bigger but it also makes the detection really inaccurate when dealing with multiple players. For single player games it may work just fine, since you may just need to ignore collision only against the primary player.

Hello everyone,

We’ve been trying to develop an accurate hit detection system for a melee-based game.
So far we’ve found some glaring issues and need some help to get us going in the right direction.

Specifics

We’re trying to get accurate hit detection using very fast animations. Most of the attack animations are about 1-2 seconds in length. This includes the windup, swing, and blend back to idle. The part we care about is the swing, which is about 2-3 frames of that animation. We’re having issues reliably detecting whether or not the weapon has collided with the object.

What we’ve tried

Method 1: Attaching a collision box/capsule to the weapon

This is the most straight-forward one, so its the one we went with first. We attached collision to the weapon, then played an animation montage for the swing. The issue was that with the fast animation speed, the collision box wouldn’t register a hit against the other player reliably (pictured below with my super awesome illustration).

Method 2: Traces along the weapon body

This is the method we’ve seen suggested that was used in Chivalry. This involves tracing points along the length of the weapon and comparing them against previous points in the animation to get a sort of swing path.
So this is what our implementation translated to:

The Problem:

This method is super frame dependent although slightly better than the first method. If your framerate dips a bit for whichever reason, the animation might skip a bit, or the game might hang for a second, which will absolutely destroy the trace’s reliability. The above example shows it works fine with a single player, and nothing else running, but this isn’t going to work reliably if the player has anything bogging down their machine even slightly.
(Ex: having the EventGraph open will kill performance. Pictured Below)

65985-linetraceproblem_s.png

Method 3: Pre-computed collision path

This was a method we came up with for dealing with the accuracy/reliability part. It involves measuring the animation path in an external 3d package by hand, making a mesh out of it, then importing it back and attaching it as a component of the character. When the player begins the swing, the collision is “turned on” through an animNotify and the damage is dealt. (Pictured below)

The Problem

While this works extremely reliably, the amount of manual work needed per animation, per weapon, gets way outta hand, way too quickly (especially since we want combo’s). This would involve turning on/off dozens of weapon collision path meshes for each possible attack.

Conclusions

So we’ve found a way to do this reliably, but with terrible scaling, and a two ways to do it more procedurally, but would involve slowing down the animation speeds to a crawl to get any reliability out of them.

Does anyone have any suggestions for a better way to accomplish this?

tldr

Animations are too fast for accurate collision based detection/traces, making custom collision paths per weapon, per animation gets ridiculous fast.

Hey,

I don’t have any specific answers for you but the problem you’ve described is one I’ve been thinking about since I know there is a chance it might affect my own project somewhere down the line.

One possibility I can think of that might be a reasonable balance between procedural generation and accuracy is to maybe widen the collision on the sword/weapon significantly. So how in your first illustration the collision is the thickness of the blade perhaps try making it 5 times wider? I may have overlooked something though

As another note have you tried any of the collision settings such as bUseCCD? I don’t know much about that sort of thing but though I should ask just incase!

Ah, sorry I can’t be of more help. It’s a very interesting problem, It’d be great if there was some way to do a continuous sweeps on movement inherited from parent but I imagine it just doesn’t work that way.

I really liked your idea with the custom collision mesh but like you say generating as many of those as you may end up needing is too time consuming.

Hey again,

Have you had a look over this thread?

https://forums.unrealengine.com/showthread.php?62016-How-to-make-collision-detection-for-fast-melee-combat

I haven’t gone over it fully yet but it seems to be talking about the same concept and has some posts from Rama so there’s bound to be some good info.

Looking over it I see they mostly talk about the same chivalry style tracing between frames you mentioned.

How about using your second method just saving the points into the blueprint before hand, and checking them in the blueprint that way even if the animation skip, the result should not change.
And man thanks for your way of thinking building something similar but in single player will be a huge help from your examples :smiley:

That sounds like it could work actually. I’ll give it a try and update with my findings.

That totally worked!

We ended up doing the following:

  • Playing the animation at a slower speed to capture the trace points.
  • Printing those points to the log, and saving them to a csv file
  • Having the weapon read those points and store them
  • When the animation is called, split those points by the total animation time, and trace to each point.

That got us to a pretty good point. We just need to start optimizing the workflow.

Doing it this way also is super accurate, if you play the game using slomo, you’ll see the traces hitting at the correct times!

Does the approach that ddemon gave mean that if the weapon swings and misses enemy, but enemy moves in range after swing has passed him mean he will still get hit?

It actually doesn’t.

If you play back the traces at the same speed as your swing, then by the time your enemy has closed in, the previous traces would have already completed, meaning no hit against your enemy was registered :slight_smile: