In this case the pawn that the AI is trying to see is the player character. Apologies… it is playerPawn as shown below - I used shorthand. This is in a B-Tree Service node component.
Now I have determined:
A) the player pawn is always found . Player pawn is set at the beginning of the tickNode method as: APawn* playerPawn = UGameplayStatics::GetPlayerPawn(GetWorld(),0);
A log statement under that fires if the pawn does not have a value (that log statement is never seen - the if always evaluates the playerPawn as having a valid pointer)
B) the AI Controller is always found. There is a line that states: if (OwnerComp.GetAIOwner() == nullptr) that will then log out the ai owner was not found and then return out.
In both of these cases we always have a player pointer, and we always have an AI Owning Controller on the object in question.
However LineOfSightTo(playerPawn) always returns false even if player Pawn is standing right next to the AI pawn.
UMyBTService_PlayerLocationIfSeen::UMyBTService_PlayerLocationIfSeen()
{
NodeName = "Set Current Player If Seen";
}
void UMyBTService_PlayerLocationIfSeen::TickNode(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds)
{
Super::TickNode(OwnerComp, NodeMemory, DeltaSeconds);
APawn* playerPawn = UGameplayStatics::GetPlayerPawn(GetWorld(), 0);
if (playerPawn == nullptr) return;
if (OwnerComp.GetAIOwner() == nullptr) return;
if (OwnerComp.GetAIOwner()->LineOfSightTo(playerPawn))
{
OwnerComp.GetBlackboardComponent()->SetValueAsObject(GetSelectedBlackboardKey(), playerPawn);
}
else
{
OwnerComp.GetBlackboardComponent()->ClearValue(GetSelectedBlackboardKey());
}
}
The if statement checking line of sight is my issue. The false branch always fires and when I add logging around it, confirmed that LineOfSightTo is always false no matter where player controller is in the scene.
To reiterate: this code works 100% on the original dev machine.
Alright, thanks for posting your code, I don’t see a problem with what you currently have. But I have an idea that could show you where the problem is, are you by any chance using an editor which can use Breakpoints? If so, please put a breakpoint on the function it calls, that would be AAIController::LineOfSightTo() and post an image of where it is returning false.
Nope. I know I can get it from the git but I don’t appear to have the source of the engine in this project. Thats something that escapes me in terms of how to do.
You could create a new class that inherits from AIController, reparent the class that you posted into the new class you created, override the LineOfSightTo function, copy the code below, and put a breakpoint there.
bool AMyNewAIController::LineOfSightTo(const AActor* Other, FVector ViewPoint, bool bAlternateChecks) const
{
if (Other == nullptr)
{
return false;
}
if (ViewPoint.IsZero())
{
FRotator ViewRotation;
GetActorEyesViewPoint(ViewPoint, ViewRotation);
// if we still don't have a view point we simply fail
if (ViewPoint.IsZero())
{
return false;
}
}
FVector TargetLocation = Other->GetTargetLocation(GetPawn());
FCollisionQueryParams CollisionParams(SCENE_QUERY_STAT(LineOfSight), true, this->GetPawn());
CollisionParams.AddIgnoredActor(Other);
bool bHit = GetWorld()->LineTraceTestByChannel(ViewPoint, TargetLocation, ECC_Visibility, CollisionParams);
if (!bHit)
{
return true;
}
// if other isn't using a cylinder for collision and isn't a Pawn (which already requires an accurate cylinder for AI)
// then don't go any further as it likely will not be tracing to the correct location
const APawn * OtherPawn = Cast<const APawn>(Other);
if (!OtherPawn && Cast<UCapsuleComponent>(Other->GetRootComponent()) == NULL)
{
return false;
}
const FVector OtherActorLocation = Other->GetActorLocation();
const float DistSq = (OtherActorLocation - ViewPoint).SizeSquared();
if (DistSq > FARSIGHTTHRESHOLDSQUARED)
{
return false;
}
if (!OtherPawn && (DistSq > NEARSIGHTTHRESHOLDSQUARED))
{
return false;
}
float OtherRadius, OtherHeight;
Other->GetSimpleCollisionCylinder(OtherRadius, OtherHeight);
if (!bAlternateChecks || !bLOSflag)
{
//try viewpoint to head
bHit = GetWorld()->LineTraceTestByChannel(ViewPoint, OtherActorLocation + FVector(0.f, 0.f, OtherHeight), ECC_Visibility, CollisionParams);
if (!bHit)
{
return true;
}
}
if (!bSkipExtraLOSChecks && (!bAlternateChecks || bLOSflag))
{
// only check sides if width of other is significant compared to distance
if (OtherRadius * OtherRadius / (OtherActorLocation - ViewPoint).SizeSquared() < 0.0001f)
{
return false;
}
//try checking sides - look at dist to four side points, and cull furthest and closest
FVector Points[4];
Points[0] = OtherActorLocation - FVector(OtherRadius, -1 * OtherRadius, 0);
Points[1] = OtherActorLocation + FVector(OtherRadius, OtherRadius, 0);
Points[2] = OtherActorLocation - FVector(OtherRadius, OtherRadius, 0);
Points[3] = OtherActorLocation + FVector(OtherRadius, -1 * OtherRadius, 0);
int32 IndexMin = 0;
int32 IndexMax = 0;
float CurrentMax = (Points[0] - ViewPoint).SizeSquared();
float CurrentMin = CurrentMax;
for (int32 PointIndex = 1; PointIndex<4; PointIndex++)
{
const float NextSize = (Points[PointIndex] - ViewPoint).SizeSquared();
if (NextSize > CurrentMin)
{
CurrentMin = NextSize;
IndexMax = PointIndex;
}
else if (NextSize < CurrentMax)
{
CurrentMax = NextSize;
IndexMin = PointIndex;
}
}
for (int32 PointIndex = 0; PointIndex<4; PointIndex++)
{
if ((PointIndex != IndexMin) && (PointIndex != IndexMax))
{
bHit = GetWorld()->LineTraceTestByChannel(ViewPoint, Points[PointIndex], ECC_Visibility, CollisionParams);
if (!bHit)
{
return true;
}
}
}
}
return false;
}
I’m going to guess that this means there are differences in what the original machine has, versus what the source control depot has.
If you don’t have engine debugging capability (because you’re not installed from source), it mioght be difficult to debug into it to see what’s failing.
However, here’s the code for LOSTo, and maybe you can glean something from there
bool AAIController::LineOfSightTo(const AActor* Other, FVector ViewPoint, bool bAlternateChecks) const
{
if (Other == nullptr)
{
return false;
}
if (ViewPoint.IsZero())
{
FRotator ViewRotation;
GetActorEyesViewPoint(ViewPoint, ViewRotation);
// if we still don't have a view point we simply fail
if (ViewPoint.IsZero())
{
return false;
}
}
FVector TargetLocation = Other->GetTargetLocation(GetPawn());
FCollisionQueryParams CollisionParams(SCENE_QUERY_STAT(LineOfSight), true, this->GetPawn());
CollisionParams.AddIgnoredActor(Other);
bool bHit = GetWorld()->LineTraceTestByChannel(ViewPoint, TargetLocation, ECC_Visibility, CollisionParams);
if (!bHit)
{
return true;
}
// if other isn't using a cylinder for collision and isn't a Pawn (which already requires an accurate cylinder for AI)
// then don't go any further as it likely will not be tracing to the correct location
const APawn * OtherPawn = Cast<const APawn>(Other);
if (!OtherPawn && Cast<UCapsuleComponent>(Other->GetRootComponent()) == NULL)
{
return false;
}
const FVector OtherActorLocation = Other->GetActorLocation();
const float DistSq = (OtherActorLocation - ViewPoint).SizeSquared();
if (DistSq > FARSIGHTTHRESHOLDSQUARED)
{
return false;
}
if (!OtherPawn && (DistSq > NEARSIGHTTHRESHOLDSQUARED))
{
return false;
}
float OtherRadius, OtherHeight;
Other->GetSimpleCollisionCylinder(OtherRadius, OtherHeight);
if (!bAlternateChecks || !bLOSflag)
{
//try viewpoint to head
bHit = GetWorld()->LineTraceTestByChannel(ViewPoint, OtherActorLocation + FVector(0.f, 0.f, OtherHeight), ECC_Visibility, CollisionParams);
if (!bHit)
{
return true;
}
}
if (!bSkipExtraLOSChecks && (!bAlternateChecks || bLOSflag))
{
// only check sides if width of other is significant compared to distance
if (OtherRadius * OtherRadius / (OtherActorLocation - ViewPoint).SizeSquared() < 0.0001f)
{
return false;
}
//try checking sides - look at dist to four side points, and cull furthest and closest
FVector Points[4];
Points[0] = OtherActorLocation - FVector(OtherRadius, -1 * OtherRadius, 0);
Points[1] = OtherActorLocation + FVector(OtherRadius, OtherRadius, 0);
Points[2] = OtherActorLocation - FVector(OtherRadius, OtherRadius, 0);
Points[3] = OtherActorLocation + FVector(OtherRadius, -1 * OtherRadius, 0);
int32 IndexMin = 0;
int32 IndexMax = 0;
float CurrentMax = (Points[0] - ViewPoint).SizeSquared();
float CurrentMin = CurrentMax;
for (int32 PointIndex = 1; PointIndex<4; PointIndex++)
{
const float NextSize = (Points[PointIndex] - ViewPoint).SizeSquared();
if (NextSize > CurrentMin)
{
CurrentMin = NextSize;
IndexMax = PointIndex;
}
else if (NextSize < CurrentMax)
{
CurrentMax = NextSize;
IndexMin = PointIndex;
}
}
for (int32 PointIndex = 0; PointIndex<4; PointIndex++)
{
if ((PointIndex != IndexMin) && (PointIndex != IndexMax))
{
bHit = GetWorld()->LineTraceTestByChannel(ViewPoint, Points[PointIndex], ECC_Visibility, CollisionParams);
if (!bHit)
{
return true;
}
}
}
}
return false;
}
edit: i completely failed to notice someone else already supplied that before i hit reply