ApplyRadialDamage not working properly!

Hello.

When my Rocket explodes, it has to Apply a Radial Damage which extends for a certain space with a specified radius.

For this reason I decided to use the UGameplayStatics::ApplyRadialDamage() function

BUG N°1 -> The damage is not fully applied



void AProjectile::Explode(const FHitResult& HitResult)
{
	const FVector ImpactLocation = HitResult.ImpactPoint + HitResult.ImpactNormal * 10.0f;

	// Apply a [radial damage] 
	if (OwnerWeapon->ProjectileConfig.ExplosionDamage > 0 && OwnerWeapon->ProjectileConfig.ExplosionRadius > 0 && OwnerWeapon->ProjectileConfig.DamageType)
	{
		UGameplayStatics::ApplyRadialDamage(this, OwnerWeapon->ProjectileConfig.**ExplosionDamage**, ImpactLocation, OwnerWeapon->ProjectileConfig.ExplosionRadius, OwnerWeapon->ProjectileConfig.DamageType, TArray<AActor*>(), OwnerWeapon->GetWeaponOwner());
	}
}


The **ExplosionDamage **has a value of 100

The Health of the Character is 100.

When I hit the Character with one single Rocket he *should *die immediately: instead, he remains alive with somehealth.

Pay attention: I said “with **SOME **health”.

This means the Character sometimes is left with 13 health, sometimes with 12, 20, 22… it’s inconsistent!

BUG N°2 -> I can’t inflict damage to myself!

When I shoot at my feets (or in nearby areas) I don’t get any damage!

Any tips?

1 Like

BUG N°1:

I see nothing wrong with the engine code. It seems You don’t know how to use it. Radial damage use Falloff which means damage will fade with distance.

You should tweak explosion radius/damage and correct impact location, usually projectile hit to character CapsuleComponent or physical asset.

Hint: falloff can be ignored if bFullDamage is set to true;

BUG N°2:
By default UGameplayStatics::ApplyRadialDamage will not cause damage to DamageCauser, in your case DamageCauser == OwnerWeapon->GetWeaponOwner();

I wonder why won’t you debug it yourself, You have full engine source :slight_smile:

   @Pierdek I'm sorry if you misunderstood. It's not the Engine I claim to have bugs, it's my game :p

I need the Falloff. And, if the Missile directly hits the player, **the player should get the 100% of the Radial Damage **

That doesn’t happen.

I’m having a double edged sword here.

I do want the DamageCauser to be considered during the hit process (the classic ‘haha you killed yourself’).

The ApplyRadialDamage() provides a parameter for specifying a pointer to the Actor to **IGNORE **during the hit process.
I pass a NULL pointer (nullptr) since I want nothing to be ignored.

BUT, how do I prove chain of the Actor who actually shot the Missile?

Let’s say I hit a player character. The character class has the TakeDamage() function which gets called by ApplyRadialDamage() by default.

In that TakeDamage() function I need to do a check like this (pseudocode)



float MyCharacterClass::TakeDamage(float Damage, struct FDamageEvent const& DamageEvent, class AController* EventInstigator, **class AActor* DamageCauser**)
{
    if( DamageCauser == me )
        Oh, I shot to myself, let's apply damage to myself
     
    else
        Oh, that villain hit me with a Missile!
}


The problem is… since I pass a nullptr in the ApplyRadialDamage function, then DamageCauser will be nullptr. How do I refer to the original shooter?

Take a look:



bool UGameplayStatics::ApplyRadialDamage(UObject* WorldContextObject, float BaseDamage, const FVector& Origin, float DamageRadius, TSubclassOf<UDamageType> DamageTypeClass, const TArray<AActor*>& IgnoreActors, AActor* DamageCauser, AController* InstigatedByController, bool bDoFullDamage, ECollisionChannel DamagePreventionChannel )
{
    float DamageFalloff = bDoFullDamage ? 0.f : 1.f;
    return ApplyRadialDamageWithFalloff(WorldContextObject, BaseDamage, 0.f, Origin, 0.f, DamageRadius, DamageFalloff, DamageTypeClass, IgnoreActors, DamageCauser, InstigatedByController, DamagePreventionChannel);
}

bool UGameplayStatics::ApplyRadialDamageWithFalloff(UObject* WorldContextObject, float BaseDamage, float MinimumDamage, const FVector& Origin, float DamageInnerRadius, float DamageOuterRadius, float DamageFalloff, TSubclassOf<class UDamageType> DamageTypeClass, const TArray<AActor*>& IgnoreActors, AActor* DamageCauser, AController* InstigatedByController, ECollisionChannel DamagePreventionChannel)
{
    static FName NAME_ApplyRadialDamage = FName(TEXT("ApplyRadialDamage"));
    FCollisionQueryParams SphereParams(NAME_ApplyRadialDamage, false, DamageCauser);

    SphereParams.AddIgnoredActors(IgnoreActors);

// query scene to see what we hit
	TArray<FOverlapResult> Overlaps;
	UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject);
	World->OverlapMultiByObjectType(Overlaps, Origin, FQuat::Identity, FCollisionObjectQueryParams(FCollisionObjectQueryParams::InitType::AllDynamicObjects), FCollisionShape::MakeSphere(DamageOuterRadius), SphereParams);

...


I see 3 ways to do what You want:

  1. Pass nullptr as DamageCauser, so the Overlap will not ignore this actor, use AController* InstigatedByController instead and check in Your TakeDamage function class AController* EventInstigator.
  2. Take into account direct hit in order to apply full damage: for directly hit actor call UGameplayStatics::ApplyDamage or UGameplayStatics::ApplyRadialDamage with bFullDamage param then call UGameplayStatics::ApplyRadialDamage pass DamageCauser as before.
  3. Write Your custom UGameplayStatics::ApplyRadialDamage :slight_smile:

The ApplyRadialDamage depends on a FHitResult reference variable.

I know I can obtain the Actor that was directly hit by using the HitResult.**Actor ** attribute.

But I need to cast that Actor to my Character class



AMyCharacter* DamagedPlayer = Cast<AMyCharacter>(HitResult.Actor);


This unfortunately says:

1.jpg

But in Blueprints that is legal:

2.jpg

:confused:

AMyCharacter* DamagedPlayer = Cast<AMyCharacter>(HitResult.Actor.Get());

Yes, that was the solution.

Do you know, by chance, how to convert the location of an Actor to a FHitResult variable?

There is specialized constructor to create FHitResult from limited data



/** Ctor for easily creating "fake" hits from limited data. */
FHitResult(class AActor* InActor, class UPrimitiveComponent* InComponent, FVector const& HitLoc, FVector const& HitNorm);



(I don’t have a time to check which data is actually used for applying damage), something like this should work:



FHitResult MyHitResult(HitActor,HitComponent,FVector(0.f,0.f,0.f),FVector(0.f,0.f,1.f));