Why Line Trace Single doesn't work?

Hi everyone !

I am trying to create a weapon system in UE4 in C++. So I have a Weapon class which is supposed to trace a line from the muzzle of the weapon skeletal mesh muzzle socket, to the first actor it meet. This is why I use the LineTraceSingle function. But, it doesn’t work ! When I shoot in game, it always do like if it never meet an actor : Hit.EndTrace is always (0,0,0), and the function return also a false boolean. Here is a part of my source file :

void AWeapon::TraceToAim()
{
	GEngine->AddOnScreenDebugMessage(-1, .5f, FColor::Red, TEXT("shoot"));
	// Calculate the start and the end of the trace (everything works here)
	const int32 RandomSeed = FMath::Rand();
	FRandomStream WeaponRandomStream(RandomSeed);
	const float CurrentSpread = WeaponData.WeaponSpread;
	const float SpreadCone = FMath::DegreesToRadians(CurrentSpread * 0.5);
	const FVector AimDir = Mesh->GetSocketRotation("MuzzleSocket").Vector();
	const FVector StartTrace = Mesh->GetSocketLocation("MuzzleSocket");
	const FVector ShootDir = WeaponRandomStream.VRandCone(AimDir, SpreadCone, SpreadCone);
	const FVector EndTrace = StartTrace + ShootDir * WeaponData.WeaponRange;

	// Actors to ignore
	TArray<AActor*> ActorsToIgnore;
	ActorsToIgnore.Add(Instigator);
	ActorsToIgnore.Add(this);
	if (isHandle && WeaponOwner != NULL)
	{
		ActorsToIgnore.Add(WeaponOwner);
	}

	FHitResult Hit(ForceInit);

	bool success = Trace(ActorsToIgnore, StartTrace, EndTrace, Hit);

	UE_LOG(LogTemp, Warning, TEXT("Cone direction : %s ;Maximal shooting location : %s ;Hit objective : %s"), *AimDir.ToString(), *EndTrace.ToString(), *Hit.TraceEnd.ToString());

	if (!success)
	{
		Hit.TraceEnd = EndTrace;
		UE_LOG(LogTemp, Warning, TEXT("Fail"));
	}
	else
		UE_LOG(LogTemp, Warning, TEXT("Success !"));


	// Fire
	DrawDebugLine(this->GetWorld(), StartTrace, Hit.TraceEnd, FColor::Black, true, 10000.f, 10.f);
}

bool AWeapon::Trace(
	TArray<AActor*>& ActorsToIgnore,
	const FVector& Start,
	const FVector& End,
	FHitResult& HitOut,
	ECollisionChannel CollisionChannel,
	bool ReturnPhysMat) 
{
	if (ActorsToIgnore.Num() <= 0) return false;
	if (ActorsToIgnore[0] == NULL) return false;

	FCollisionQueryParams TraceParams(FName(TEXT("Weapon Trace")), true, ActorsToIgnore[0]);
	TraceParams.bTraceComplex = true;

	//TraceParams.bTraceAsyncScene = true;
	TraceParams.bReturnPhysicalMaterial = ReturnPhysMat;

	//Ignore Actors
	TraceParams.AddIgnoredActors(ActorsToIgnore);

	//Re-initialize hit info
	HitOut = FHitResult(ForceInit);

	ActorsToIgnore[0]->GetWorld()->LineTraceSingle(
		HitOut,		//result
		Start,	//start
		End, //end
		CollisionChannel, //collision channel
		TraceParams);

	return (HitOut.GetActor() != NULL);
}

And here is my log when I shoot :

I hope you will be able to help me !
Thank you !

What’s CollisionChannel defaulting to? Do the objects you’re colliding with have that channel set in their collision properties?

The function use the CollisionChannel ECC_Pawn. How do you set a collision channel in the actor’s properties ?

Look for “Collision Presets” in your actor’s properties. If it’s a typical character, you’ll see two collision presets: one of the mesh, and one for the capsule around the mesh.

I use a static mesh actor (a big cube with a collision box attach to it) to do my tests. When I put every collision behavior to “block”, and the object type to “Pawn”, it is still not working.

Does this help ?

Okay, I don’t think you want ECC_Pawn, since that’s an object response, not a trace response. Your default choices for trace responses are ECC_Camera or ECC_Visibility.

Personally, I define my own trace channels, which you can do in the “Collision” section of your project settings. These are defined in code as ECC_GameTraceChannel1, 2, 3, etc, so you should defined a better name in one of your header files like so:

#define TRACE_STATIC_MESH        ECC_GameTraceChannel1

No it is still not working. I tried using ECC_Visibility, ECC_Camera or ECC_GameTraceChannel1 instead of ECC_Pawn in the CollisionChannel parameter of my trace function, but it always return a false value. Here is the collision properties of my static mesh I am trying to colliding to :

Thank you for helping me again !

Ok I discovered something weird. So I was looking into the shooter example game and the WeaponTrace function. I used it with my my game and it works in a strange way …

The line trace function (in the WeaponTrace function) return a true result and the Hit.EndTrace is not (0,0,0) as always but the maximal distance of the race. So it says that it is colliding but in fact the end result in not colliding with an object. I hope it is clear enough.

Here is my code :

void AWeapon::TraceToAim()
{
	// Calcul direction, cible et origine du tir ...
	const int32 RandomSeed = FMath::Rand();
	FRandomStream WeaponRandomStream(RandomSeed);
	const float CurrentSpread = WeaponData.WeaponSpread;
	const float SpreadCone = FMath::DegreesToRadians(CurrentSpread * 0.5);
	const FVector AimDir = Mesh->GetSocketRotation("MuzzleSocket").Vector();
	const FVector StartTrace = Mesh->GetSocketLocation("MuzzleSocket");
	const FVector ShootDir = WeaponRandomStream.VRandCone(AimDir, SpreadCone, SpreadCone);
	const FVector EndTrace = StartTrace + ShootDir * WeaponData.WeaponRange;

	// Actor à ignorer dans le traçage de la cible de l'arme
	TArray<AActor*> ActorsToIgnore;
	ActorsToIgnore.Add(Instigator);
	ActorsToIgnore.Add(this);
	if (isHandle && WeaponOwner != NULL)
	{
		ActorsToIgnore.Add(WeaponOwner);
	}

	FHitResult Hit = WeaponTrace(StartTrace, EndTrace);

	UE_LOG(LogTemp, Warning, TEXT("Cone direction : %s ;Maximal shooting location : %s ;Hit objective : %s"), *AimDir.ToString(), *EndTrace.ToString(), *Hit.TraceEnd.ToString());


	// Fire
	DrawDebugLine(this->GetWorld(), StartTrace, Hit.TraceEnd, FColor::Black, true, 1000.f, 10.f);
	InstantFire(Hit);
}

FHitResult AWeapon::WeaponTrace(const FVector & StartTrace, const FVector & EndTrace) const
{
	static FName WeaponFireTag = FName(TEXT("WeaponTrace"));

	// Perform trace to retrieve hit info
	FCollisionQueryParams TraceParams(WeaponFireTag, true, Instigator);
	TraceParams.bTraceAsyncScene = true;
	TraceParams.bReturnPhysicalMaterial = true;

	FHitResult Hit(ForceInit);
	if (GetWorld()->LineTraceSingle(Hit, StartTrace, EndTrace, TRACE_WEAPON, TraceParams))
		UE_LOG(LogTemp, Warning, TEXT("Success !"));

	return Hit;
}

Sorry my code is a bit messy !

In the log it shows “Success !”, and the Hit.EndTrace is the same as TraceEnd vector.

Do you know why it is working like this ?

I finally solved the problem !
It was just because I was using Hit.TraceEnd instead of Hit.Location.
Now everything is perfectly working !