Fix EQS firing position: invalid BB vector check, AlreadyAtGoal fallback

- LastKnownTargetPosition check now filters FLT_MAX/InvalidLocation (not just zero)
- EQS result with AlreadyAtGoal triggers fallback advance instead of no-op
- bProjectGoal enabled for EQS move to handle NavMesh projection

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
j.foucher 2026-03-29 11:14:04 +02:00
parent 59a23e61db
commit 25abd59512
8 changed files with 34 additions and 16 deletions

View File

@ -227,8 +227,12 @@ void UPS_AI_Behavior_BTTask_Attack::TickTask(
{
// No LOS and idle → find a firing position
// Check if investigation (last known position) is active
// ClearValue sets vectors to FAISystem::InvalidLocation, not zero — must check both
const FVector LastKnownPos = BB->GetValueAsVector(PS_AI_Behavior_BB::LastKnownTargetPosition);
if (!LastKnownPos.IsZero())
const bool bHasLastKnown = !LastKnownPos.IsZero() &&
!LastKnownPos.ContainsNaN() &&
LastKnownPos.X < 1e30f; // Filter out FLT_MAX / InvalidLocation
if (bHasLastKnown)
{
// Investigation mode: go to last known position
AIC->MoveToLocation(
@ -336,6 +340,7 @@ void UPS_AI_Behavior_BTTask_Attack::TickTask(
*AIC->GetName());
}
}
}
EBTNodeResult::Type UPS_AI_Behavior_BTTask_Attack::AbortTask(
@ -427,20 +432,9 @@ void UPS_AI_Behavior_BTTask_Attack::OnFiringPositionQueryFinished(
AActor* Target = WeakTarget.Get();
if (Result.IsValid() && Result->IsSuccessful())
// Fallback lambda: advance directly toward target
auto FallbackAdvance = [&](const TCHAR* Reason)
{
const FVector FiringPos = Result->GetItemAsLocation(0);
AIC->MoveToLocation(
FiringPos, 50.0f, /*bStopOnOverlap=*/true,
/*bUsePathfinding=*/true, /*bProjectGoal=*/false, /*bCanStrafe=*/false);
Memory->bSeekingFiringPos = true;
UE_LOG(LogPS_AI_Behavior, Log, TEXT("[%s] Attack: EQS found firing position %s"),
*AIC->GetName(), *FiringPos.ToString());
}
else
{
// EQS found nothing — fallback: advance toward target
if (Target)
{
const float MidRange = (Memory->MinRange + Memory->MaxRange) * 0.5f;
@ -449,9 +443,32 @@ void UPS_AI_Behavior_BTTask_Attack::OnFiringPositionQueryFinished(
/*bUsePathfinding=*/true, /*bProjectGoal=*/true, /*bCanStrafe=*/false);
Memory->bSeekingFiringPos = true;
}
UE_LOG(LogPS_AI_Behavior, Log, TEXT("[%s] Attack: %s, fallback advance toward target"),
*AIC->GetName(), Reason);
};
UE_LOG(LogPS_AI_Behavior, Log, TEXT("[%s] Attack: EQS no result, fallback advance"),
*AIC->GetName());
if (Result.IsValid() && Result->IsSuccessful())
{
const FVector FiringPos = Result->GetItemAsLocation(0);
const EPathFollowingRequestResult::Type MoveResult = AIC->MoveToLocation(
FiringPos, 50.0f, /*bStopOnOverlap=*/true,
/*bUsePathfinding=*/true, /*bProjectGoal=*/true, /*bCanStrafe=*/false);
if (MoveResult == EPathFollowingRequestResult::RequestSuccessful)
{
Memory->bSeekingFiringPos = true;
UE_LOG(LogPS_AI_Behavior, Log, TEXT("[%s] Attack: EQS moving to firing position %s"),
*AIC->GetName(), *FiringPos.ToString());
}
else
{
// AlreadyAtGoal or Failed — EQS position is too close or unreachable
FallbackAdvance(TEXT("EQS position unreachable or too close"));
}
}
else
{
FallbackAdvance(TEXT("EQS no result"));
}
}

View File

@ -48,6 +48,7 @@ public:
UPROPERTY(EditAnywhere, Category = "Attack|LOS", meta = (ClampMin = "0.1", ClampMax = "1.0"))
float LOSCheckInterval = 0.2f;
/**
* EQS query asset for finding a firing position with clear LOS.
* Compose in editor: OnCircle generator + LineOfSight filter + Distance tests.