What is the best way to do melee weapon collision?

I’ve been looking around the documentation and I found out that the most used approach is to trace from two bones in the weapon each frame and detect if it collides something, but I’ve personally tested this and this type of detection seems to rely a lot on the framerate your game is running at and if the weapon doesn’t hit something in a rendered frame, it doesn’t count as a hit.
Isn’t there any other more accurate or framerate independent way of checking weapon collision? I’m sure there must be another way.

Watch the 3rd Person tutorial on you tube (the series by Unreal Engine). There’s a whole section on ‘punching’. All you have to do is put a collision box around the part that does damage and then use Blueprints to make it do damage.

It depends: do you need information about the hit? For example, the location it connects to spawn particles, or the angle of impact to trigger reaction animations? Or do you just need to know “there was a hit”?

For the latter, using simple colliders and OnBeginOverlap messages is the best way, bar none.

For the former, it’s a little trickier, but in my opinion the best approach is the one used by Super Smash Bros; you “coat” the surface of the attacking weapon with sockets such that if you were to attach sphere components to each one, those spheres would make a pretty good rough outline of the shape of the weapon. Then, every frame, you do a swept sphere trace to the current position of each socket from its position in the previous frame. Since you’re using spheres, this system remains accurate even if the weapon is rotating from frame to frame (using a single box or capsule collider doesn’t work since swept shape tests can’t rotate the shape during the sweep).

This requires some additional logic setup though; every frame, you need to remember if a hit was registered by one of the traces. Once a hit registers, you need to disregard all other hits until a frame occurs where NO hits register (without this step, a sword might swing two of its spheres through an enemy across two frames and yield a total of four registered hits for a single impact).

Frankly I think that the overlap test is far superior but UE4 doesn’t report any sort of hit result data on overlaps (no inpact location or normal) and if you need that data, frame-by-frame sweeps are really the only way to go, unfortunately.

3 Likes

Thing is that with that approach other problems arise. You can put a box around the object, but then I won’t be getting the impact normal and other useful things. Plus, a box is a kinda crappy way to detect collision. I’d rather use some sort of more “automatic” way.

I do need to get the impact location and all the Hit Result stuff, so using a box or a sphere isn’t the way to go for me.

So, for this frame-to-frame sweep, you store the position of each socket on current frame (except obviously the first frame compared as that one doesn’t have a “previous frame”) and in the next frame you make the spheres extend from previous frame position to the current?

So, like this? (Crappy paint drawing incoming)

&stc=1

Then you check if something has been hit. If it has been hit you include it in a “Exclude actors” so you don’t hit the same actor twice in the same animation. Is that right?
However, I feel that this is kinda cheap as the weapon doesn’t really extend that far. Can’t you do like a hit test with physics? Like if I make my weapon a skeletal mesh, wouldn’t I be able to use the actual mesh as a collision component or something?

You can always try to get the estimated intersection ‘point’ of the two rectangles, give it a look - you might want to research a little better, I just googled this quickly, not sure if its suitable:

Yes, your drawing is correct, though using “exclude actors” may not be the best way to filter subsequent hits (you might be able to get clever with a DoOnce node, it depends on your specific setup)

Hit tests with physics won’t work because the weapon will (I assume) be attached to a skeletal socket; this makes it fully kinematic, and its position will not ever be defined by physics as it won’t be simulating. This prevents it from firing Hit messages at all, since it can’t really HIT anything (the animation can and will drive it right through potential colliding enemies).

It’s true this isn’t FULLY accurate but in all honesty it’s probably the best you could approximate it, and FWIW it’s already more accurate than most melee systems in games today, which use single large spherical overlaps in the general position of the weapon swing to determine contact rather than frame-by-frame comparisons (Fortnite does this, for example).

I’m taking a similar approach, converting a fire weapon into melee weapon by shooting a ‘Spark’ projectile from a bone/sock in the handle. The idea is to have greater control of speed and size of a projectile and particle systems. At this point its strictly theory.

I have also been thinking on making a melee engine, based on collision boxes. Issue is, how on earth will we get the specific collision point/area/plane? Its needed for obvious reasons: particles, per-bone hits and so forth.

Hi,

Check UWorld for sweep test functions, you can use those to test collision and proper FHitResult will be returned.


SweepSingleByChannel
(
    FHitResult & OutHit,
    const FVector & Start,
    const FVector & End,
    const FQuat & Rot,
    ECollisionChannel TraceChannel,
    const FCollisionShape & CollisionSh...,
    const FCollisionQueryParams & Param...,
    const FCollisionResponseParams & Re...
)

I don’t have UE4 access in here, but in theory, volumes also register onHit events, which in turn, already have hit location calculation, correct? With this in mind, if one uses the onHit event instead of overlapping events to calculate melee hits, then it should be fairly straightforward to retrieve the hit location.

Yeah but hit events NECESSARILY include the depenetration of the two colliding bodies.

An animation which drives a capsule or box collider through an enemy cannot produce OnHit events, by definition.
It might be possible to, instead of using attachment, sweep the collider shape to a new location each tick, but even if this accounted for rotation properly (and it doesn’t, sweeping never does) the shape would get stuck on the enemy and break collision detection thereafter, which is not intended behavior.

As far as I’ve found out so far, its a really expensive operation - to obtain the overlapping area, which I suggested.
After a quick google search I’ve found the following (check the links in the comments throughout the threads)

Regarding your depenetration sentence, what exactly does that mean? The volume will ‘return’ back to its position before the hit? Will it freeze there? Or will it simply not produce overlap events?

What I mean is in order for a Hit event to register, an object must make CONTACT, meaning the engine must have determined that it has touched another object and is not allowed to pass through. A Hit is a collision event and it only fires if one object stops the movement of another object. By depenetration I refer to the fact that a hit event only fires on those collisions where the engine is attempting to PREVENT objects from overlapping/penetrating.

A melee system does not work this way. A sword swings directly through an enemy when you attack with it, at least in every game I’ve ever played. Enemies might have a reaction animation, but the engine is not actually calculating a point of contact like it would for, say, a trash can being thrown into a wall. It’s not possible in UE to get Hit data from movements like this; if the animation has total control over the location of the collider (via attachment), then a Hit cannot occur because the physics/collision detection portion of the engine isn’t doing anything. It isn’t detecting penetration between two objects and putting a stop to it, so no Hit is ever generated.

Now, I’m not saying that there isn’t a way of getting the relevant Hit Result data when dealing with overlaps, either manually with math or by modifying the low-level code involved, but WRT to Blueprints unless an actual collision takes place (meaning two objects touch which are not allowed to pass through one another) you will not get a Hit Result. Event Hit will simply never fire.