Customized EQS Mills – Assume And Construct


EQS in UE4 comes with a very good set of mills of question gadgets however there may be instances the place you like to create mills tailor-made in your wants.
I made a decision to write down my very own generator as a result of I needed to write a question to seek out the very best place across the querier however not too near it. I knew that I might simply add a distance exams to increment rating with distance however I didn’t even wish to think about gadgets inside a sure vary from the querier so I ended up with a customized generator that produces a gap across the querier location. Here’s a comparability between the Easy Grid Genrator accessible within the UE4 EQS system and my generator.

As you’ll be able to see the Easy Grid Generator produces a sq.. Whereas our Easy Grid Offset Generator produces a sq. with a gap.


As an alternative of subclassing the Easy Grid Generator I made a decision to start out from a primary subclass of UEnvQueryGenerator_ProjectedPoints(the bottom kind for all the opposite shapes mills). I discovered extraordinarily helpful to make use of Unreal Engine code as start line for my implementation and I’ve primarily applied my generator following the unique code of the Easy Grid Generator, including the logic to create the outlet within the grid.

Let’s undergo every wanted step to create this class.


Listed here are the parameters wanted to outline the generator:
OffsetSpace: is the house that defines the dimensions of the outlet.
GridHalfSize: is the dimensions of the grid.
SpaceBetween: is the house that defines the gap between every merchandise.

The info kind for these values is FAIDataProviderFloatValue. It is a particular information kind that inherits from FAIDataProviderValue. This information kind wraps a worth (int, float or bool) round a struct including logic for information binding.
In a couple of world it is possible for you to to edit this parameter from one other useful resource and replace generator gadgets at run time. Extra information on this matter at this hyperlink.
and a blueprint instance right here.

In case you aren’t on this choice you should utilize a easy float.
Right here is the code of the header that defines these parameters.

class AMyController : public AAIController

Straight from the UE4 documentation:
“…a Generator such because the Easy Grid Generator can use a Context that returns a number of places or Actors. This may create a Easy Grid, of the outlined measurement and density, on the location of every Context.”

Clearly we don’t wish to lose the power to outline customized context that aren’t simply the querier. So let’s add a brand new parameter of kind subclassof UEnvQueryContext. It’s going to come in useful quickly after we will generate the gadgets.

UPROPERTY(EditDefaultsOnly, Class = Generator)
TSubclassOf GenerateAround;


The primary perform accountable to create the gadgets for our generator is GenerateItems, and it’s outlined within the UEnvQueryGenerator class.
We’ll override it including our customized code.

The very first thing to do right here is to bind generator parameters to the question occasion to have the ability to use information binding on this generator:

UObject* BindOwner = QueryInstance.Proprietor.Get();
GridHalfSize.BindData(BindOwner, QueryInstance.QueryID);
SpaceBetween.BindData(BindOwner, QueryInstance.QueryID);
OffsetSpace.BindData(BindOwner, QueryInstance.QueryID);

then we will seize the present worth for this parameter (you should definitely use the GetValue perform as a substitute of attempting to entry the worth straight):

float RadiusValue = GridHalfSize.GetValue();
float DensityValue = SpaceBetween.GetValue();
float OffsetValue = OffsetSpace.GetValue();

With the subsequent a part of code we’ll lastly create the question gadgets, following this 3 factors :
1 – calculate the entire gadgets quantity (making an allowance for the potential of a number of contexts)
2 – calculate every merchandise place
3 – Challenge all factors and take away these exterior the present navmesh and retailer the end result.

The code is kind of trivial, right here yow will discover these three steps defined with feedback:

// Get variety of gadgets per row and calculate the indexes ranges for the outlet
const int32 ItemsCount = FPlatformMath::TruncToInt((RadiusValue * 2.0 / DensityValue) + 1);
const int32 ItemsCountHalf = ItemsCount / 2;
const int32 LeftRangeIndex = ItemsCountHalf - FPlatformMath::TruncToInt(OffsetValue / DensityValue) - 1;
const int32 RightRangeIndex = ItemsCountHalf + FPlatformMath::TruncToInt(OffsetValue / DensityValue) + 1;
const int32 OffsetItemsCount = FPlatformMath::TruncToInt((ItemsCount * 2.0 / DensityValue) + 1);

// Get places for every context (we would have extra that one context)
TArray<FVector> ContextLocations;
QueryInstance.PrepareContext(GenerateAround, ContextLocations);

// Reserve the wanted reminiscence house of things for every context.
// the entire gadgets depend is calculated subtracting the gadgets situated into the outlet from the entire checklist of things. 
TArray<FNavLocation> GridPoints;
GridPoints.Reserve(((ItemsCount * ItemsCount) - (OffsetItemsCount * OffsetItemsCount)) * ContextLocations.Num());
// Calculate place of every merchandise
for (int32 ContextIndex = 0; ContextIndex < ContextLocations.Num(); ContextIndex++) {
	for (int32 IndexX = 0; IndexX < ItemsCount; ++IndexX)
		for (int32 IndexY = 0; IndexY < ItemsCount; ++IndexY)
			// it the merchandise is inside the outlet ranges, simply skip it.
			if ((IndexY > LeftRangeIndex && IndexY < RightRangeIndex) && (IndexX > LeftRangeIndex && IndexX < RightRangeIndex)) 
			// ranging from the context location, outline the placement of the present merchandise 
			// and add it to the gridPoints array.
			else {
				const FNavLocation TestPoint = FNavLocation(ContextLocations[ContextIndex] - FVector(DensityValue * (IndexX - ItemsCountHalf), DensityValue * (IndexY - ItemsCountHalf), 0));
// Challenge all of the factors, take away these exterior the present navmesh and retailer the end result.
ProjectAndFilterNavPoints(GridPoints, QueryInstance);
StoreNavPoints(GridPoints, QueryInstance);


The ultimate contact is given by the features GetDescriptionTitle and GetDescriptionDetails. They’ll simply add a textual description straight seen within the EQS editor. The outline and title will change relying on the worth chosen by the developer within the editor.

I’m taking the features as is from easy grid generator including the offset info.

FText UEnvQueryGenerator_GridOffset::GetDescriptionTitle() const
	return FText::Format(LOCTEXT("GridOffsetDescriptionGenerateAroundContext", "{0}: generate round {1}"),
		Tremendous::GetDescriptionTitle(), UEnvQueryTypes::DescribeContext(GenerateAround));

FText UEnvQueryGenerator_GridOffset::GetDescriptionDetails() const
	FText Desc = FText::Format(LOCTEXT("GridOffseDescription", "radius: {0}, house between: {1}, offset:{2}"),
		FText::FromString(GridHalfSize.ToString()), FText::FromString(SpaceBetween.ToString()), FText::FromString(OffsetSpace.ToString()));

	FText ProjDesc = ProjectionData.ToText(FEnvTraceData::Temporary);
	if (!ProjDesc.IsEmpty())
		FFormatNamedArguments ProjArgs;
		ProjArgs.Add(TEXT("Description"), Desc);
		ProjArgs.Add(TEXT("ProjectionDescription"), ProjDesc);
		Desc = FText::Format(LOCTEXT("GridOffsetDescriptionWithProjection", "{Description}, {ProjectionDescription}"), ProjArgs);

	return Desc;


For those who open the EQS editor you will notice that our new generator is offered within the mills checklist and you should utilize it precisely as the opposite official mills.

You could find the complete code for this tutorial on GitHub.
Be at liberty to poke me on Twitter or write a remark right here.



Leave a Comment