Visible raycasts

I have a question regarding raycasts through C++. When I do raycasts through blueprint, I can choose the option of making those traces visible, which I think is rather useful. However, when I try to do raycasts through c++, the functions available don’t give any options for visualizing it. I tried lifting the functionality from the Kismet library (adding the necessary enums and everything), but when I try to perform a trace, all that happens is that the game crashes.

Copied trace code


void DrawDebugSweptSphere(const UWorld* InWorld, FVector const& Start, FVector const& End, float Radius, FColor const& Color, bool bPersistentLines = false, float LifeTime = -1.f, uint8 DepthPriority = 0)
{
	FVector const TraceVec = End - Start;
	float const Dist = TraceVec.Size();

	FVector const Center = Start + TraceVec * 0.5f;
	float const HalfHeight = (Dist * 0.5f) + Radius;

	FQuat const CapsuleRot = FRotationMatrix::MakeFromZ(TraceVec).ToQuat();
	::DrawDebugCapsule(InWorld, Center, HalfHeight, Radius, CapsuleRot, Color, bPersistentLines, LifeTime, DepthPriority);
}

bool MyGame::SphereTraceSingle(UObject* WorldContextObject, const FVector Start, const FVector End, float Radius, ECollisionChannel TraceChannel, bool bTraceComplex, const TArray<AActor*>& ActorsToIgnore, EDrawDebugTraceInternal::Type DrawDebugType, FHitResult& OutHit, bool bIgnoreSelf)
{
	//lifted from KismetSystemLibrary.cpp so that I have visual traces from within c++

	static const FName SphereTraceSingleName(TEXT("SphereTraceSingle"));
	static const float DEBUG_DRAW_DURATION = 5.f;
	static const float DEBUG_IMPACTPOINT_SIZE = 16.f;

	FCollisionQueryParams Params(SphereTraceSingleName, bTraceComplex);
	Params.bReturnPhysicalMaterial = true;
	Params.bTraceAsyncScene = true;
        if (ActorsToIgnore.Num() != 0)
	      Params.AddIgnoredActors(ActorsToIgnore);
	if (bIgnoreSelf)
	{
		AActor* IgnoreActor = Cast<AActor>(WorldContextObject);
		if (IgnoreActor)
		{
			Params.AddIgnoredActor(IgnoreActor);
		}
		else
		{
			// find owner
			UObject* CurrentObject = WorldContextObject;
			while (CurrentObject)
			{
				CurrentObject = CurrentObject->GetOuter();
				AActor* IgnoreActor = Cast<AActor>(CurrentObject);
				if (IgnoreActor)
				{
					Params.AddIgnoredActor(IgnoreActor);
					break;
				}
			}
		}
	}

	UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject);
	bool const bHit = World->SweepSingle(OutHit, Start, End, FQuat::Identity, TraceChannel, FCollisionShape::MakeSphere(Radius), Params);

	if (DrawDebugType != EDrawDebugTraceInternal::None)
	{
		bool bPersistent = DrawDebugType == EDrawDebugTraceInternal::Persistent;
		float LifeTime = (DrawDebugType == EDrawDebugTraceInternal::ForDuration) ? DEBUG_DRAW_DURATION : 0.f;

		if (bHit && OutHit.bBlockingHit)
		{
			// Red up to the blocking hit, green thereafter
			::DrawDebugSweptSphere(World, Start, OutHit.Location, Radius, FColor::Red, bPersistent, LifeTime);
			::DrawDebugSweptSphere(World, OutHit.Location, End, Radius, FColor::Green, bPersistent, LifeTime);
			::DrawDebugPoint(World, OutHit.ImpactPoint, DEBUG_IMPACTPOINT_SIZE, FColor::Red, bPersistent, LifeTime);
		}
		else
		{
			// no hit means all red
			::DrawDebugSweptSphere(World, Start, End, Radius, FColor::Red, bPersistent, LifeTime);
		}
	}

	return bHit;
}

and the trace



void MyGame::Tick(float DeltaSeconds)
{
	FHitResult TestHit;
	FVector HitStart = GetActorLocation() + (GetActorForwardVector()*32.f);
	FVector HitEnd = GetActorLocation() + (GetActorForwardVector()*48.f);
	const TArray<AActor*> ActorsToIgnore;
	

	bool bHitResult = SphereTraceSingle(NULL, HitStart, HitEnd, 32.f, ECC_Visibility, false, ActorsToIgnore, EDrawDebugTraceInternal::ForDuration, TestHit, true);
}

What do I need to do to make this code work and, most of all, stop crashing the game?

The WorldContextObject has to be a UObject with a valid UWorld pointer. Try passing this instead of NULL:



	bool bHitResult = SphereTraceSingle(this, HitStart, HitEnd, 32.f, ECC_Visibility, false, ActorsToIgnore, EDrawDebugTraceInternal::ForDuration, TestHit, true);


Yeah, that solved the problem beautifully. Thanks!