Melee damage

Hi, is there a way to apply melee damage in C++? I read this: A new, community-hosted Unreal Engine Wiki - Announcements and Releases - Unreal Engine Forums but I need that the damage is for the players in front of the damage causer, and not for all players near the damage causer.

Just start with that approach and add a dot product check to exclude actors outside whatever frontal angle you want.

Thanks for the reply, but what do you mean for “dot product check”? Excuse me for my ignorance. :slight_smile:

It’s basic linear algebra, you’ll have a hard time doing gameplay math without knowing it!

The dot product is one of the two most important operations you can do with vectors, the other being the cross product. Without going into the proofs and theory, one interesting property of the dot product comes from this definition:


With |X| being the length of X, |Y| the length of Y and theta the angle between the two vectors. The cosine of a 0 degree angle is 1, the cosine of a 90 degree angle is 0, and the cosine of a 180 degree angle is -1. What this means is that you can use the dot product to compare two vectors and check the resulting sign to see if the vectors are pointing in the same direction, are perpendicular or opposite. As a result:


FVector CharacterDirection = MyCharacter->GetActorRotation().Vector();
FVector DeltaToEnemy = Enemy->GetActorLocation() - MyCharacter->GetActorLocation();
FVector DirectionToEnemy = DeltaToEnemy.SafeNormal();

float DotToEnemy = FVector::DotProduct( CharacterDirection, DirectionToEnemy );

if( DotToEnemy > 0.0f )
{
    // enemy is in front, do stuff here
}

This is a very common thing to do and you’ll probably be using it a lot. An important note is the normalization (SafeNormal) being done – this transforms the length of the vector to be 1, thus eliminating the length arguments from the definition above and makes sure you are only dealing with the cosine. For just a sign check, this isn’t actually necessary, but it comes in handy if you want to further specialize your check. For instance:


FVector CharacterDirection = MyCharacter->GetActorRotation().Vector();
FVector DeltaToEnemy = Enemy->GetActorLocation() - MyCharacter->GetActorLocation();
FVector DirectionToEnemy = DeltaToEnemy.SafeNormal();

float DotToEnemy = FVector::DotProduct( CharacterDirection, DirectionToEnemy );

const float MaxMeleeAngle = FMath::DegreesToRadians( 45.0f );
const float MaxMeleeCos = FMath::Cos( MaxMeleeAngle );

if( DotToEnemy > MaxMeleeCos )
{
    // enemy is in melee arc, do stuff here
}

If your vectors are not normalized, then the result of the dot product will be multiplied by |DirectionToEnemy|, leading to bad results.

The dot product and cross product (and linear algebra in general) are pretty important, I’d recommend reading on it if you want to do game programming.

Thanks for the comprehensive explanation. To solve the problem I traced a line and I saw what actors are hitted by the line.
But the problem is that the shot doesn’t match the crosshair, as you can see here:

http://puu.sh/dGW4D/beea104da2.jpg

The code is this:


FHitResult MeleeHitResult;
	FCollisionQueryParams TraceParams;
	TraceParams.bTraceComplex = false;
	TraceParams.bReturnPhysicalMaterial = true;
	TraceParams.bTraceAsyncScene = true;
	TraceParams.AddIgnoredActor(this);
	GetWorld()->LineTraceSingle(MeleeHitResult, FirstPersonCameraComponent->GetComponentLocation(), (FirstPersonCameraComponent->GetForwardVector() * 50000) + FirstPersonCameraComponent->GetComponentLocation(), ECC_Visibility, TraceParams);
        DrawDebugLine(GetWorld(), FirstPersonCameraComponent->GetComponentLocation(), (FirstPersonCameraComponent->GetForwardVector() * 50000) + FirstPersonCameraComponent->GetComponentLocation(), FColor::Blue, false, 5.f, 0, 0.f);
	DrawDebugSphere(GetWorld(), MeleeHitResult.ImpactPoint, 20, 20, FColor::Blue, false, 5.f);

Ah, yeah, trace based melee attacks are a wholly different bag. It is more finnicky and complicated than generic overlaps like the original approach, but it definitely gives better results. For instance, swinging a sword will have hits actually occur when they collide with something rather than just a single moment when the attack “connects”.

In any event, your problem’s pretty simple. Here is your screenshot in Photoshop with guides placed at the exact centre of the viewport:

http://i.imgur.com/LM3axPyl.jpg

The trace is actually correct, it’s the crosshairs that’s not centered correctly. Remember that the position of UI elements is normally on their top left corner. So when centering a UI element, you have to factor in the element’s own size when setting its location.

If you’re using a UMG/Slate canvas, it’s as simple as setting the alignment to (0.5, 0.5), which will treat the crosshairs’s “origin” as being in the middle rather than the default top left (0.0, 0.0 alignment). If you’re using a FCanvas HUD, then do the math manually:


	const FVector2D Center( Canvas->ClipX * 0.5f, Canvas->ClipY * 0.5f );
	const FVector2D Position = Center **- CrosshairsSize * 0.5f;**

It works. Thanks, you are the best!