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?