I’m attempting a raycast to find a point of collision, and I’m using LineTraceSingle().
UWorld* const world = GetWorld();
const TArray<AActor*> actors_to_ignore;
FHitResult hit;
FLinearColor line_color = FLinearColor(0, 0, 255, 255);
FLinearColor impact_color = FLinearColor(255, 0, 0, 255);
start = FVector(1000, -1000, 300);
end = FVector(500, -1000, 300);
UKismetSystemLibrary::LineTraceSingle(world, start, end, ETraceTypeQuery::TraceTypeQuery1, false, actors_to_ignore, EDrawDebugTrace::None, hit, true, line_color, impact_color, 1);
However, the FHitResult keeps returning these results:
Distance 0.00000000
Location X=0.00000000 Y=0.00000000 Z=0.00000000
ImpactPoint X=0.00000000 Y=0.00000000 Z=0.00000000
This happens regardless of the start and end positions I calculate. Currently I have them hardcoded to the middle of a room that is known to be empty. I can’t help but feel I’m using LineTraceSingle() incorrectly, but I’m not sure where I’m going wrong. Alternatively, I’m open to suggestions if there’s a better function for collision raycasting.
It seems like you are setting up your raycast correctly, But make sure to verify that the objects in your scene have the correct collision settings, as the ray won’t register hits if collisions are not enabled or set up incorrectly. Additionally, consider enabling EDrawDebugTrace::ForDuration to visualize the ray for debugging purposes.
Thanks for the advice so far.
Setting EDrawDebugTrace to ForDuration did not initially result in any visual difference. The ray was not visibly being drawn.
With regards to the objects in the scene, are you referring to “Simulation generates hit events” or some other setting?
The issue is not that the ray is traveling and returning no collision where it should. The ray is not moving at all, as if it’s stuck in something solid that isn’t there. Additionally, the locations it’s reporting back aren’t along the vector of the start and end points I’m sending. If it is, indeed, trying to raycast out from (0, 0, 0), then I’m not surprised it’s failing because I believe that is inside the floor. What would cause the raycast to ignore my start and end points and default to the world origin?
As a test, I moved the floor down so it would no longer intersect with (0, 0, 0). Now I can see the ray being drawn in a blue line and fading away after a few seconds. However, the raycast is still returning distance 0, even though the visible ray clearly has length.
I’m sorry for the confusion. I’ve tested your code and just noticed that the issue lies in the hardcoded start and end points. These fixed points make the raycast static and immovable, as you pointed out. To resolve this, you can dynamically set the start point by obtaining the player’s view position. Here’s my suggested approach:
// I dont know if I would use a Cast to get the player controller as I think there is better ways but just for the purpose of the solution
APlayerController* PlayerController = Cast<APlayerController>(GetController());
// Checking if the pointer is not null
if (PlayerController != nullptr)
{
FVector CameraLocation;
FRotator CameraRotation;
// The following function is taking parameters by reference, so it will get the player view point and assign it to the camera location and camera rotation
PlayerController->GetPlayerViewPoint(CameraLocation, CameraRotation);
FVector EndLocation = CameraLocation + (CameraRotation.Vector() * 1000); // Change 1000 to your desired distance
FHitResult HitResult;
FCollisionQueryParams QueryParams;
QueryParams.AddIgnoredActor(this);
GetWorld()->LineTraceSingleByChannel(HitResult, CameraLocation, EndLocation, ECC_Visibility, QueryParams);
if (HitResult.bBlockingHit)
{
// We hit something. You can access information about the hit using HitResult.
// For example, HitResult.GetActor() contains the actor that we hit.
UE_LOG(LogTemp, Warning, TEXT("You hit: %s"), *HitResult.GetActor()->GetName());
}
// Draw a debug line to visualize the raycast
DrawDebugLine(GetWorld(), CameraLocation, EndLocation, FColor::Red, false, 2, 0, 1);
}
You’ll notice that this approach is more resilient, and while it might appear intricate, it’s primarily due to the fact that I’m employing LineTraceSingleByChannel
directly instead of relying on the Kismet Library to handle the parameters automatically. However, for a rapid and effortless method of performing traces, utilizing the KismetLibrary is a convenient choice.
The hardcoded endpoints were actually on purpose, for debugging reasons. I wasn’t trying to get a collision - I was trying to avoid one.
After messing around with LineTraceSingleByChannel() and moving around some things in the level, I’ve concluded this stems from a misunderstanding on my part about what the hit results mean.
I assumed a non-hit would return the full length of the raycast as Distance along with the starting point as Location. If the ray doesn’t collide with anything, then the ray should complete its journey and report back as such. This isn’t true. If there’s no collision, those fields aren’t populated and they just return 0. This is counterintuitive to me because it makes it seem like the ray travelled 0 distance, implying the starting point was inside something solid.
It seems like both functions work as expected if they DO hit something.