FHitResult AGameplayAbilityTargetActor_GroundTrace::PerformTrace(AActor* InSourceActor) { static const FName LineTraceSingleName(TEXT("AGameplayAbilityTargetActor_GroundTrace")); bool bTraceComplex = false; FCollisionQueryParams Params(LineTraceSingleName, bTraceComplex); Params.bReturnPhysicalMaterial = true; Params.bTraceAsyncScene = true; Params.AddIgnoredActor(InSourceActor); FVector TraceStart = StartLocation.GetTargetingTransform().GetLocation();// InSourceActor->GetActorLocation(); FVector TraceEnd; AimWithPlayerController(InSourceActor, Params, TraceStart, TraceEnd); //Effective on server and launching client only // ------------------------------------------------------ FHitResult ReturnHitResult; //Use a line trace initially to see where the player is actually pointing LineTraceWithFilter(ReturnHitResult, InSourceActor->GetWorld(), Filter, TraceStart, TraceEnd, TraceProfile.Name, Params); //Default to end of trace line if we don't hit anything. if (!ReturnHitResult.bBlockingHit) { ReturnHitResult.Location = TraceEnd; } //Second trace, straight down. Consider using InSourceActor->GetWorld()->NavigationSystem->ProjectPointToNavigation() instead of just going straight down in the case of movement abilities (flag/bool). TraceStart = ReturnHitResult.Location - (TraceEnd - TraceStart).GetSafeNormal(); //Pull back very slightly to avoid scraping down walls TraceEnd = TraceStart; TraceStart.Z += CollisionHeightOffset; TraceEnd.Z -= 99999.0f; LineTraceWithFilter(ReturnHitResult, InSourceActor->GetWorld(), Filter, TraceStart, TraceEnd, TraceProfile.Name, Params); //if (!ReturnHitResult.bBlockingHit) then our endpoint may be off the map. Hopefully this is only possible in debug maps. bLastTraceWasGood = true; //So far, we're good. If we need a ground spot and can't find one, we'll come back. //Use collision shape to find a valid ground spot, if appropriate if (CollisionShape.ShapeType != ECollisionShape::Line) { ReturnHitResult.Location.Z += CollisionHeightOffset; //Rise up out of the ground TraceStart = InSourceActor->GetActorLocation(); TraceEnd = ReturnHitResult.Location; TraceStart.Z += CollisionHeightOffset; bLastTraceWasGood = AdjustCollisionResultForShape(TraceStart, TraceEnd, Params, ReturnHitResult); if (bLastTraceWasGood) { ReturnHitResult.Location.Z -= CollisionHeightOffset; //Undo the artificial height adjustment } } if (AGameplayAbilityWorldReticle* LocalReticleActor = ReticleActor.Get()) { LocalReticleActor->SetIsTargetValid(bLastTraceWasGood); LocalReticleActor->SetActorLocation(ReturnHitResult.Location); } // Reset the trace start so the target data uses the correct origin ReturnHitResult.TraceStart = StartLocation.GetTargetingTransform().GetLocation(); return ReturnHitResult; }
void AGameplayAbilityTargetActor_Trace::AimWithPlayerController(const AActor* InSourceActor, FCollisionQueryParams Params, const FVector& TraceStart, FVector& OutTraceEnd, bool bIgnorePitch) const { if (!OwningAbility) // Server and launching client only { return; } APlayerController* PC = OwningAbility->GetCurrentActorInfo()->PlayerController.Get(); check(PC); FVector ViewStart; FRotator ViewRot; PC->GetPlayerViewPoint(ViewStart, ViewRot); const FVector ViewDir = ViewRot.Vector(); FVector ViewEnd = ViewStart + (ViewDir * MaxRange); ClipCameraRayToAbilityRange(ViewStart, ViewDir, TraceStart, MaxRange, ViewEnd); FHitResult HitResult; LineTraceWithFilter(HitResult, InSourceActor->GetWorld(), Filter, ViewStart, ViewEnd, TraceProfile.Name, Params); const bool bUseTraceResult = HitResult.bBlockingHit && (FVector::DistSquared(TraceStart, HitResult.Location) <= (MaxRange * MaxRange)); const FVector AdjustedEnd = (bUseTraceResult) ? HitResult.Location : ViewEnd; FVector AdjustedAimDir = (AdjustedEnd - TraceStart).GetSafeNormal(); if (AdjustedAimDir.IsZero()) { AdjustedAimDir = ViewDir; } if (!bTraceAffectsAimPitch && bUseTraceResult) { FVector OriginalAimDir = (ViewEnd - TraceStart).GetSafeNormal(); if (!OriginalAimDir.IsZero()) { // Convert to angles and use original pitch const FRotator OriginalAimRot = OriginalAimDir.Rotation(); FRotator AdjustedAimRot = AdjustedAimDir.Rotation(); AdjustedAimRot.Pitch = OriginalAimRot.Pitch; AdjustedAimDir = AdjustedAimRot.Vector(); } } OutTraceEnd = TraceStart + (AdjustedAimDir * MaxRange); }
FHitResult AGameplayAbilityTargetActor_SingleLineTrace::PerformTrace(AActor* InSourceActor) { static const FName LineTraceSingleName(TEXT("AGameplayAbilityTargetActor_SingleLineTrace")); bool bTraceComplex = false; TArray<AActor*> ActorsToIgnore; ActorsToIgnore.Add(InSourceActor); FCollisionQueryParams Params(LineTraceSingleName, bTraceComplex); Params.bReturnPhysicalMaterial = true; Params.bTraceAsyncScene = true; Params.AddIgnoredActors(ActorsToIgnore); FVector TraceStart = StartLocation.GetTargetingTransform().GetLocation();// InSourceActor->GetActorLocation(); FVector TraceEnd; AimWithPlayerController(InSourceActor, Params, TraceStart, TraceEnd); //Effective on server and launching client only // ------------------------------------------------------ FHitResult ReturnHitResult; LineTraceWithFilter(ReturnHitResult, InSourceActor->GetWorld(), Filter, TraceStart, TraceEnd, TraceProfile.Name, Params); //Default to end of trace line if we don't hit anything. if (!ReturnHitResult.bBlockingHit) { ReturnHitResult.Location = TraceEnd; } if (AGameplayAbilityWorldReticle* LocalReticleActor = ReticleActor.Get()) { LocalReticleActor->SetActorLocation(ReturnHitResult.Location); LocalReticleActor->SetIsTargetAnActor(ReturnHitResult.bBlockingHit && (ReturnHitResult.Actor != NULL)); } if (bDebug) { DrawDebugLine(GetWorld(), TraceStart, TraceEnd, FColor::Green); DrawDebugSphere(GetWorld(), TraceEnd, 100.0f, 16, FColor::Green); } return ReturnHitResult; }