x

Search in
Sort by:

Question Status:

Search help

  • Simple searches use one or more words. Separate the words with spaces (cat dog) to search cat,dog or both. Separate the words with plus signs (cat +dog) to search for items that may contain cat but must contain dog.
  • You can further refine your search on the search results page, where you can search by keywords, author, topic. These can be combined with each other. Examples
    • cat dog --matches anything with cat,dog or both
    • cat +dog --searches for cat +dog where dog is a mandatory term
    • cat -dog -- searches for cat excluding any result containing dog
    • [cats] —will restrict your search to results with topic named "cats"
    • [cats] [dogs] —will restrict your search to results with both topics, "cats", and "dogs"

Sweep trace is not returning correct hit locations

Since the radial damage functions don't have any effect in my game, I have been trying to implement my own version, but I am running into a problem when a perform a sweep. More specifically, when I run a multi sweep, I do get a full array of all the objects that were within the sweep radius, but all the objects impact points return the same value of the first object in the array. This majorly complicates things, as I need the impact point of all the separate objects within the trace to calculate damage falloff and that doesn't really work when all I get is the same location for every single object in the trace.

I have tried this both with c++ and blueprint, in both version 4.14 and 4.15, and they all have the same effect, so I am submitting this as a bug.

 void UPA_BlueprintFunctionLibrary::DealRadialDamageWithFalloff(float MinDamage, float MaxDamage, float MinRadius, float MaxRadius, float FallOff, FVector DamageOrigin, TSubclassOf<UDamageType> DamageType, class AController* InstigatedBy, AActor* DamageCauser, FHitResult HitResult, bool bIgnoreSelf, bool bDebug)
 {
     if (MaxRadius != 0.f && DamageCauser)
     {
         FCollisionQueryParams initialTraceParams(TEXT(""), false, DamageCauser);
         initialTraceParams.bTraceAsyncScene = true;
         initialTraceParams.bTraceComplex = true;
         initialTraceParams.bReturnPhysicalMaterial = false;
 
         TArray<FHitResult> HitResults;
 
         FCollisionObjectQueryParams ObjectParams;
         ObjectParams.AddObjectTypesToQuery(ECC_Pawn);
         ObjectParams.AddObjectTypesToQuery(ECC_WorldStatic);
         ObjectParams.AddObjectTypesToQuery(ECC_WorldDynamic);
         ObjectParams.AddObjectTypesToQuery(ECC_Visibility);
 
         bool bHit = DamageCauser->GetWorld()->SweepMultiByObjectType(HitResults, 
             DamageOrigin, 
             FVector(DamageOrigin.X, DamageOrigin.Y, DamageOrigin.Z + 1.f), 
             FQuat::Identity, 
             ObjectParams, 
             FCollisionShape::MakeSphere(MaxRadius), 
             initialTraceParams);
 
         if (bDebug)
         {
             DrawDebugSphere(DamageCauser->GetWorld(), DamageOrigin, MinRadius, 12, FColor::Red, false, 2.f);
             DrawDebugSphere(DamageCauser->GetWorld(), DamageOrigin, MaxRadius, 12, FColor::Blue, false, 2.f);
         }
 
         if (bHit)
         {
             for (int32 HitIndex = 0; HitIndex < HitResults.Num(); HitIndex++)
             {
                 if (bIgnoreSelf && HitResults[HitIndex].GetActor() == DamageCauser)
                 {
                     //do nothing
                 }
                 else
                 {
                     float ActorDistance = (DamageOrigin - HitResults[HitIndex].ImpactPoint).Size();
 
                     float const ValidatedMinRadius = FMath::Max(0.f, MinRadius);
                     float const ValidatedMaxRadius = FMath::Max(MaxRadius, ValidatedMinRadius);
                     float const ValidatedDistance = FMath::Max(0.f, ActorDistance);
 
                     // calculate the interpolated scale
                     float DamageScale;
 
                     if (ValidatedDistance >= ValidatedMaxRadius)
                     {
                         DamageScale = 0.f;
                     }
                     else if ((FallOff == 0.f) || (ValidatedDistance <= ValidatedMinRadius))
                     {
                         DamageScale = 1.f;
                     }
                     else
                     {
                         DamageScale = 1.f - ((ValidatedDistance - ValidatedMinRadius) / (ValidatedMaxRadius - ValidatedMinRadius));
                         DamageScale = FMath::Pow(DamageScale, FallOff);
                     }
 
                     float ActualDamage = FMath::Lerp(MinDamage, MaxDamage, FMath::Max(0.f, DamageScale));

 
                     DrawDebugPoint(DamageCauser->GetWorld(), HitResults[HitIndex].ImpactPoint, 20.f, FColor::Green, false, 2.f);
 
                     if (ActualDamage > 0.f)
                         UGameplayStatics::ApplyDamage(HitResults[HitIndex].GetActor(), ActualDamage, InstigatedBy, DamageCauser, DamageType);
                 }
             }
         }
     }
 }
Product Version: UE 4.15
Tags:
more ▼

asked Mar 10 '17 at 08:45 AM in Bug Reports

avatar image

cridia
815 29 24 103

avatar image Doug E ♦♦ STAFF Mar 10 '17 at 03:02 PM

Hey cridia-

If I understand correctly, your hit location and impact point are returning the same value? Can you check if bStartPenetrating is true? Based on your description, it sounds like you're having the same issue that is described here: https://answers.unrealengine.com/questions/421052/sweep-collision-doesnt-work-if-the-start-loc-and-e.html . Let me know if the information from Zak M, including the use of UBodySetup::GetClosestPointAndNormal(), helps. If not, can you provide the full setup steps to reproduce the behavior you're seeing? Either the blueprint setup used to test or the full code / class structure that the function you provided is used in.

avatar image cridia Mar 13 '17 at 07:26 AM

My apologies for the late reply.

I doublechecked, and bStartPenetrating is returning true for every object in the array.

I have tried implementing UBodySetup::GetClosestPointAndNormal(), but the function is giving me a warning when being called ("LogPhysics:Warning: GetClosestPointAndNormalImpl ClosestDist for BodySetup BodySetup /Game/Geometry/Meshes/1M_Cube.1M_Cube:BodySetup_5 is coming back as FLT_MAX."). This is how I implemented it;

 FVector NewImpactPoint, NewImpactNormal;
     
 if (UBodySetup* BodySetup = HitResults[HitIndex].GetComponent()->GetBodySetup())
 {
 BodySetup->GetClosestPointAndNormal(DamageOrigin, HitResults[HitIndex].GetComponent()->GetComponentTransform(), NewImpactPoint, NewImpactNormal);
 
 DrawDebugPoint(DamageCauser->GetWorld(), NewImpactPoint, 20.f, FColor::Blue, false, 4.f);    
 }
avatar image cridia Mar 13 '17 at 07:27 AM

As for how the UPA_BlueprintFunctionLibrary is implemented in code (I removed the unnecessary bits, since the reply was getting too big);

 if (BlahBlah)
 {
     FCollisionObjectQueryParams ObjectParams;
     ObjectParams.AddObjectTypesToQuery(ECollisionChannel::ECC_Visibility);
     ObjectParams.AddObjectTypesToQuery(ECollisionChannel::ECC_Pawn);
     ObjectParams.AddObjectTypesToQuery(ECollisionChannel::ECC_WorldStatic);
     ObjectParams.AddObjectTypesToQuery(ECollisionChannel::ECC_WorldDynamic);
 
     FCollisionQueryParams TraceParams(TEXT(""), false, ToolOwner);
     TraceParams.bTraceAsyncScene = true;
     TraceParams.bTraceComplex = true;
     TraceParams.bReturnPhysicalMaterial = true;
 
     FVector MuzzleLoc = GetSocketLocation(MuzzleSocket);
     FRotator MuzzleRot = GetSocketRotation(MuzzleSocket);
     FVector TargetLoc = MuzzleLoc + (FRotationMatrix(MuzzleRot).GetScaledAxis(EAxis::X) * Range);
     TargetLoc.X = ToolOwner->GetActorLocation().X;
 
     FHitResult TraceHit(ForceInit);
 
     bool bHit = GetWorld()->LineTraceSingleByObjectType(TraceHit, MuzzleLoc, TargetLoc, ObjectParams, TraceParams);
 
     if (bHit)
     {
         UPA_BlueprintFunctionLibrary::DealRadialDamageWithFalloff(0.f,
             Damage,
             CurrentFlintlockBullet.InnerRadius,
             CurrentFlintlockBullet.OuterRadius,
             CurrentFlintlockBullet.FallOff,
             TraceHit.ImpactPoint,
             CurrentFlintlockBullet.DamageType,
             ToolOwner->GetController(),
             ToolOwner,
             TraceHit,
             false,
             true
         );
     }
 }
avatar image Doug E ♦♦ STAFF Mar 13 '17 at 06:08 PM

If you're still having issues with the values being returned, can you provide the blueprint setup you tested with to help ensure my local test matches the results you're seeing.

avatar image cridia Mar 14 '17 at 12:59 AM

alt text

This is how I tested the blueprint version (though I should mention that I really need my main implementation to be in C++, rather than blueprint). Something curious I found is that no matter where the trace starts, the Initial Overlap bool always returns true, even when the starting point of the trace is not even remotely close to any mesh.

While it's probably clear from the screenshot, I should also mention that the ignored actors array is empty.

sweeptracesetup.jpg (331.8 kB)
(comments are locked)
10|2000 characters needed characters left

1 answer: sort voted first

Hey cridia-

Thank you for the explaination. Using your setup I was able to determine that the issue is a combination of the size of the sphere and how the sphere is being drawn. When the sphere is large enough and/or the object that is casting the sphere (the start location) is close enough to what is being hit, the location returned for that hit is the location that was used as the starting point. I have reported this behavior here: https://issues.unrealengine.com/issue/UE-42934 .

Cheers

Doug Wilson

more ▼

answered Mar 15 '17 at 03:41 PM

(comments are locked)
10|2000 characters needed characters left
Your answer
toggle preview:

Up to 5 attachments (including images) can be used with a maximum of 5.2 MB each and 5.2 MB total.

Follow this question

Once you sign in you will be able to subscribe for any updates here

Answers to this question