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);
}
Ejemplo n.º 2
0
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);
}