void UEnvQueryGenerator_SimpleGrid::GenerateItems(FEnvQueryInstance& QueryInstance) const { UObject* BindOwner = QueryInstance.Owner.Get(); GridSize.BindData(BindOwner, QueryInstance.QueryID); SpaceBetween.BindData(BindOwner, QueryInstance.QueryID); float RadiusValue = GridSize.GetValue(); float DensityValue = SpaceBetween.GetValue(); const int32 ItemCount = FPlatformMath::TruncToInt((RadiusValue * 2.0f / DensityValue) + 1); const int32 ItemCountHalf = ItemCount / 2; TArray<FVector> ContextLocations; QueryInstance.PrepareContext(GenerateAround, ContextLocations); TArray<FNavLocation> GridPoints; GridPoints.Reserve(ItemCount * ItemCount * ContextLocations.Num()); for (int32 ContextIndex = 0; ContextIndex < ContextLocations.Num(); ContextIndex++) { for (int32 IndexX = 0; IndexX <= ItemCount; ++IndexX) { for (int32 IndexY = 0; IndexY <= ItemCount; ++IndexY) { const FNavLocation TestPoint = FNavLocation(ContextLocations[ContextIndex] - FVector(DensityValue * (IndexX - ItemCountHalf), DensityValue * (IndexY - ItemCountHalf), 0)); GridPoints.Add(TestPoint); } } } ProjectAndFilterNavPoints(GridPoints, QueryInstance); StoreNavPoints(GridPoints, QueryInstance); }
void UEnvQueryGenerator_OnCircle::GenerateItemsForCircle(uint8* ContextRawData, UEnvQueryItemType* ContextItemType, const FVector& CenterLocation, const FVector& StartDirection, int32 StepsCount, float AngleStep, FEnvQueryInstance& OutQueryInstance) const { TArray<FNavLocation> ItemCandidates; ItemCandidates.AddZeroed(StepsCount); for (int32 Step = 0; Step < StepsCount; ++Step) { ItemCandidates[Step] = FNavLocation(CenterLocation + StartDirection.RotateAngleAxis(AngleStep*Step, FVector::UpVector)); } switch (TraceData.TraceMode) { case EEnvQueryTrace::Navigation: { ANavigationData* NavData = const_cast<ANavigationData*>(FEQSHelpers::FindNavigationDataForQuery(OutQueryInstance)); if (NavData) { FEQSHelpers::RunNavRaycasts(*NavData, TraceData, CenterLocation, ItemCandidates); } } break; case EEnvQueryTrace::Geometry: FEQSHelpers::RunPhysRaycasts(OutQueryInstance.World, TraceData, CenterLocation, ItemCandidates); break; case EEnvQueryTrace::None: // Just accept the ItemCandidates as they already are (points on a circle), without using navigation OR collision. break; default: UE_VLOG(Cast<AActor>(OutQueryInstance.Owner.Get()), LogEQS, Warning, TEXT("UEnvQueryGenerator_OnCircle::CalcDirection has invalid value for TraceData.TraceMode. Query: %s"), *OutQueryInstance.QueryName); break; } ProjectAndFilterNavPoints(ItemCandidates, OutQueryInstance); AddItemDataForCircle(ContextRawData, ContextItemType, ItemCandidates, OutQueryInstance); }
void UEnvQueryGenerator_OnCircle::GenerateItemsForCircle(const FVector& CenterLocation, const FVector& StartDirection, int32 StepsCount, float AngleStep, FEnvQueryInstance& OutQueryInstance) const { TArray<FVector> ItemCandidates; ItemCandidates.AddZeroed(StepsCount); for (int32 Step = 0; Step < StepsCount; ++Step) { ItemCandidates[Step] = CenterLocation + StartDirection.RotateAngleAxis(AngleStep*Step, FVector::UpVector); } #if WITH_RECAST // @todo this needs to be optimize to batch raycasts const ARecastNavMesh* NavMesh = (TraceData.TraceMode == EEnvQueryTrace::Navigation) || (ProjectionData.TraceMode == EEnvQueryTrace::Navigation) ? FEQSHelpers::FindNavMeshForQuery(OutQueryInstance) : NULL; if (NavMesh) { NavMesh->BeginBatchQuery(); } #endif if (TraceData.TraceMode == EEnvQueryTrace::Navigation) { #if WITH_RECAST if (NavMesh != NULL) { TSharedPtr<const FNavigationQueryFilter> NavigationFilter = UNavigationQueryFilter::GetQueryFilter(NavMesh, TraceData.NavigationFilter); TArray<FNavigationRaycastWork> RaycastWorkload; RaycastWorkload.Reserve(ItemCandidates.Num()); for (const auto& ItemLocation : ItemCandidates) { RaycastWorkload.Add(FNavigationRaycastWork(CenterLocation, ItemLocation)); } NavMesh->BatchRaycast(RaycastWorkload, NavigationFilter); for (int32 ItemIndex = 0; ItemIndex < ItemCandidates.Num(); ++ItemIndex) { ItemCandidates[ItemIndex] = RaycastWorkload[ItemIndex].HitLocation.Location; } } #endif } else { ECollisionChannel TraceCollisionChannel = UEngineTypes::ConvertToCollisionChannel(TraceData.TraceChannel); FVector TraceExtent(TraceData.ExtentX, TraceData.ExtentY, TraceData.ExtentZ); FCollisionQueryParams TraceParams(TEXT("EnvQueryTrace"), TraceData.bTraceComplex); TraceParams.bTraceAsyncScene = true; FBatchTracingHelper TracingHelper(OutQueryInstance.World, TraceCollisionChannel, TraceParams, TraceExtent); switch (TraceData.TraceShape) { case EEnvTraceShape::Line: TracingHelper.DoSingleSourceMultiDestinations<EEnvTraceShape::Line>(CenterLocation, ItemCandidates); break; case EEnvTraceShape::Sphere: TracingHelper.DoSingleSourceMultiDestinations<EEnvTraceShape::Sphere>(CenterLocation, ItemCandidates); break; case EEnvTraceShape::Capsule: TracingHelper.DoSingleSourceMultiDestinations<EEnvTraceShape::Capsule>(CenterLocation, ItemCandidates); break; case EEnvTraceShape::Box: TracingHelper.DoSingleSourceMultiDestinations<EEnvTraceShape::Box>(CenterLocation, ItemCandidates); break; default: UE_VLOG(Cast<AActor>(OutQueryInstance.Owner.Get()), LogEQS, Warning, TEXT("UEnvQueryGenerator_OnCircle::CalcDirection failed to calc direction in %s. Using querier facing."), *OutQueryInstance.QueryName); break; } } #if WITH_RECAST if (NavMesh) { ProjectAndFilterNavPoints(ItemCandidates, NavMesh); NavMesh->FinishBatchQuery(); } #endif for (int32 Step = 0; Step < ItemCandidates.Num(); ++Step) { OutQueryInstance.AddItemData<UEnvQueryItemType_Point>(ItemCandidates[Step]); } }
void UEnvQueryGenerator_Donut::GenerateItems(FEnvQueryInstance& QueryInstance) const { TArray<FVector> CenterPoints; QueryInstance.PrepareContext(Center, CenterPoints); if (CenterPoints.Num() <= 0) { return; } UObject* BindOwner = QueryInstance.Owner.Get(); InnerRadius.BindData(BindOwner, QueryInstance.QueryID); OuterRadius.BindData(BindOwner, QueryInstance.QueryID); NumberOfRings.BindData(BindOwner, QueryInstance.QueryID); PointsPerRing.BindData(BindOwner, QueryInstance.QueryID); ArcAngle.BindData(BindOwner, QueryInstance.QueryID); float ArcAngleValue = ArcAngle.GetValue(); float InnerRadiusValue = InnerRadius.GetValue(); float OuterRadiusValue = OuterRadius.GetValue(); int32 NumRings = NumberOfRings.GetValue(); int32 NumPoints = PointsPerRing.GetValue(); if ((InnerRadiusValue <= 0.f) || (OuterRadiusValue <= 0.f) || (InnerRadiusValue > OuterRadiusValue) || (NumRings < 1) || (NumPoints < 1)) { return; } const float ArcBisectDeg = GetArcBisectorAngle(QueryInstance); const float ArcAngleDeg = FMath::Clamp(ArcAngleValue, 0.0f, 360.0f); const float RadiusDelta = (OuterRadiusValue - InnerRadiusValue) / (NumRings - 1); const float AngleDelta = 2.0 * PI / NumPoints; float SectionAngle = FMath::DegreesToRadians(ArcBisectDeg); TArray<FNavLocation> Points; Points.Reserve(NumPoints * NumRings); for (int32 SectionIdx = 0; SectionIdx < NumPoints; SectionIdx++, SectionAngle += AngleDelta) { if (IsAngleAllowed(SectionAngle, ArcBisectDeg, ArcAngleDeg, bDefineArc)) { const float SinValue = FMath::Sin(SectionAngle); const float CosValue = FMath::Cos(SectionAngle); float RingRadius = InnerRadiusValue; for (int32 RingIdx = 0; RingIdx < NumRings; RingIdx++, RingRadius += RadiusDelta) { const FVector RingPos(RingRadius * CosValue, RingRadius * SinValue, 0.0f); for (int32 ContextIdx = 0; ContextIdx < CenterPoints.Num(); ContextIdx++) { const FNavLocation PointPos = FNavLocation(CenterPoints[ContextIdx] + RingPos); Points.Add(PointPos); } } } } ProjectAndFilterNavPoints(Points, QueryInstance); StoreNavPoints(Points, QueryInstance); }