So I was playing around with EQS trace and wanted to trace to a location but ignore any pawns blocking the trace, I thought I could use the IgnoreOnlyPawn profile name to do the trace in EQS but found out that it doesn’t work, I took a look at the C++ implementation and correct me if I’m wrong but I think it’s not handled at all, only trace by channel is.
I thought Ok might as well try and create a slightly modified test in C++, below is my code if anyone interested, I handled the profile trace and also added an array of channels you can ignore for trace by channel.
Any suggestion/advice are welcome.
Here’s a demonstration, I’m using a context to return a location of the character rather than an actor pointer, so the trace would not ignore the character, but we can specify a channel to ignore or use a profile name.
// Fill out your copyright notice in the Description page of Project Settings.
#include "EnvQueryTest_LocationVisibility.h"
#include "EnvironmentQuery/Items/EnvQueryItemType_VectorBase.h"
#include "EnvironmentQuery/Contexts/EnvQueryContext_Querier.h"
#include "Kismet/KismetSystemLibrary.h"
UEnvQueryTest_LocationVisibility::UEnvQueryTest_LocationVisibility()
{
Cost = EEnvTestCost::High;
ValidItemType = UEnvQueryItemType_VectorBase::StaticClass();
SetWorkOnFloatValues(false);
Context = UEnvQueryContext_Querier::StaticClass();
TraceData.SetGeometryOnly();
}
void UEnvQueryTest_LocationVisibility::RunTest(FEnvQueryInstance& QueryInstance) const
{
float ItemZ = ItemHeightOffset.GetValue();
float ContextZ = ContextHeightOffset.GetValue();
bool bWantsHit = BoolValue.GetValue();
TArray<FVector> ContextLocations;
if (!QueryInstance.PrepareContext(Context, ContextLocations))
{
return;
}
FCollisionQueryParams TraceParams(SCENE_QUERY_STAT(EnvQueryTrace), TraceData.bTraceComplex);
TArray<AActor*> IgnoredActors;
if (QueryInstance.PrepareContext(Context, IgnoredActors))
{
TraceParams.AddIgnoredActors(IgnoredActors);
}
ECollisionChannel TraceCollisionChannel;
FCollisionResponseParams Response = FCollisionResponseParams::DefaultResponseParam;
FVector TraceExtent(TraceData.ExtentX, TraceData.ExtentY, TraceData.ExtentZ);
//Ignore channels, only do this if we're not using a trace by profile.
if(TraceData.TraceMode == EEnvQueryTrace::GeometryByChannel)
{
TraceCollisionChannel = UEngineTypes::ConvertToCollisionChannel(TraceData.TraceChannel);
if(IgnoreChannels.Num() > 0)
{
FCollisionResponseContainer Cnt = FCollisionResponseContainer::GetDefaultResponseContainer();
for (const ECollisionChannel ChannelToIgnore : IgnoreChannels)
{
Cnt.SetResponse(ChannelToIgnore, ECR_Ignore);
}
Response = FCollisionResponseParams(Cnt);
}
}else
{
//Load the profile once.
UCollisionProfile::GetChannelAndResponseParams(TraceData.TraceProfileName, TraceCollisionChannel, Response);
}
for (int32 ContextIndex = 0; ContextIndex < ContextLocations.Num(); ContextIndex++)
{
ContextLocations[ContextIndex].Z += ContextZ;
}
for(FEnvQueryInstance::ItemIterator It(this, QueryInstance); It; ++It)
{
const FVector ItemLocation = GetItemLocation(QueryInstance, It.GetIndex()) + FVector(0, 0, ItemZ);
AActor* ItemActor = GetItemActor(QueryInstance, It.GetIndex());
for (int32 ContextIndex = 0; ContextIndex < ContextLocations.Num(); ContextIndex++)
{
const bool Result = RunShapeTraceTo(ItemLocation, ContextLocations[ContextIndex], ItemActor, QueryInstance.World, TraceCollisionChannel, TraceParams, Response, TraceExtent, TraceData.TraceShape);
It.SetScore(TestPurpose, FilterType, Result, bWantsHit);
}
}
}
FText UEnvQueryTest_LocationVisibility::GetDescriptionTitle() const
{
return FText::FromString(TEXT("Advanced Trace"));
}
FText UEnvQueryTest_LocationVisibility::GetDescriptionDetails() const
{
return FText::FromString(TEXT("Trace by Channel/Profile"));
}
void UEnvQueryTest_LocationVisibility::PostLoad()
{
Super::PostLoad();
TraceData.OnPostLoad();
}
bool UEnvQueryTest_LocationVisibility::RunShapeTraceTo(const FVector& ItemPos, const FVector& ContextPos, AActor* ItemActor, UWorld* World, enum ECollisionChannel Channel, const FCollisionQueryParams& Params, const FCollisionResponseParams& Response, const FVector& Extent, const EEnvTraceShape::Type& Shape) const
{
FCollisionQueryParams TraceParams(Params);
TraceParams.AddIgnoredActor(ItemActor);
switch (Shape)
{
case EEnvTraceShape::Line:
return World->LineTraceTestByChannel(ItemPos, ContextPos, Channel, TraceParams, Response);
case EEnvTraceShape::Box:
return World->SweepTestByChannel(ItemPos, ContextPos, FQuat((ItemPos - ContextPos).Rotation()), Channel, FCollisionShape::MakeBox(Extent), TraceParams, Response);
case EEnvTraceShape::Sphere:
return World->SweepTestByChannel(ItemPos, ContextPos, FQuat::Identity, Channel, FCollisionShape::MakeSphere(Extent.X), TraceParams, Response);
case EEnvTraceShape::Capsule:
return World->SweepTestByChannel(ItemPos, ContextPos, FQuat::Identity, Channel, FCollisionShape::MakeCapsule(Extent.X, Extent.Z), TraceParams, Response);
default:
return false;
}
}