Blueprint to C++ and Engine Freezing?

I have an issue converting this blueprint logic to C++ is freezing the engine.

This is a working solution only if the loop runs in single mode as it is in the blueprint image

do
{
	RandomLocation(Available, Location);
} while (UsedLocations.ContainsByPredicate([Location](const FTransform Transform)
{
	return Transform.GetLocation() == Location.GetLocation()
		&& Transform.GetRotation() == Location.GetRotation()
		&& Transform.GetScale3D() == Location.GetScale3D();
}));
SpawnLocation = Location;
UsedLocations.Add(SpawnLocation);

if it runs with in the sequence of 2 steps it freezing the engine only if the logic implemented in pure C++. First i wlll show the blueprint with sequence and then C++ code which is freezin the engine.

C++ conversion which is freezing the engine.

for (auto SpawnArrayElements : ItemsIDArr)
{
	SpawnType = SpawnArrayElements.Type;
	SpawnID = SpawnArrayElements.ID;
    //Sequence 1
	ItemGroupRef->GetAllTransforms(Available);
	do
	{
		RandomLocation(Available, Location);
	} while (UsedLocations.ContainsByPredicate([Location](const FTransform Transform)
	{
		return Transform.GetLocation() == Location.GetLocation()
			&& Transform.GetRotation() == Location.GetRotation()
			&& Transform.GetScale3D() == Location.GetScale3D();
	}));
	SpawnLocation = Location;
	UsedLocations.Add(SpawnLocation);
	//Sequence 2
	switch (SpawnType)
	{
		case EItemType::E_None:
			break;

		case EItemType::E_Weapon:
		{
			APickupWeapon* NewWeaponItem = GetWorld()->SpawnActorDeferred<APickupWeapon>(PickupWeapon, SpawnLocation, nullptr, nullptr, ESpawnActorCollisionHandlingMethod::AlwaysSpawn);
			if (IsValid(NewWeaponItem))
			{
				MyGameInstanceRef->GenerateSN(SN_Wep);
				NewWeaponItem->SN = SN_Wep;
				NewWeaponItem->ID = SpawnID;
				NewWeaponItem->Ammo = 0;
				NewWeaponItem->Amount = 1;
				NewWeaponItem->FinishSpawning(SpawnLocation);
				ItemObjects.Add(NewWeaponItem);
			}
		}break;
	}
}ItemsIDArr.Empty();

.
.Cpp MyGameMode.cpp (9.7 KB)

the reason for the freez is is because the loop is always infinite since you are not giving a random range before comparing not returning any results to make the condition change in the loop.

in your .h file

bool TransformsEqual(TArray<FTransform> TransformArray, FTransform B)
{
	for (FTransform A : TransformArray)
	{
		if (A.GetScale3D() == B.GetScale3D() && A.GetLocation() == B.GetLocation() && A.GetRotation() == B.GetRotation()) 
//in your blueprint you are using only location your previous post defines, so you can check here only for location and scale in case.
		{
			return false;
		}
	}
	return true;
}

in your .cpp replace do/while loop at //Sequence 1

do 
{
  RandomLocation(Available, Location);
  UsedLocations.Add(Location);
} while (TransformsEqual(Available, Location));
SpawnLocation = Location;

test it


hope it helps
cheers!

2 Likes

Thank You very much Sir for the solution but it works only 98%, the duplicate locations are spawned , some spawn items got the same location and they are overlapping each other :tired_face:

put the loop under for (int x = 0; x < Available.Num(); x++) and let me know about the output

1 Like

i got the same results duplicated locations

looks like something wrong with your randomlocation function
can you post it please how it is implemented?

1 Like
void AMyGameMode::RandomLocation(TArray<FTransform> Available, FTransform& Location)
{
	FTransform GetByRef;
	GetByRef = Available[FMath::RandRange(1, Available.Num() - 1)];
	Location = GetByRef;
}

comment this line

change this line

auto& GetByRef = Available[FMath::RandRange(1, Available.Num() - 3)];

test it

hope it helps
cheers!

1 Like

the duplication level decreased but still the locations are duplicated

it seems to me I will never solve this problem :tired_face:

If you need truly unique locations then you’ll need some way to check for uniqueness.

I would just use a Set as they force uniqueness.

int32 DesiredNumberOfTransforms = 100;
	TSet<FTransform> Transforms;

	while(Transforms.Num() < DesiredNumberOfTransforms)
	{
		Transforms.Add(GetRandomTransformFunction());
	}

This will give you a unique set of transforms for a given range. I have not provided the “GetRandomTransform” function as you might already have one.

1 Like

Then after if you need to loop through the set to get back all your locations you can do it like so.

for(const auto& CurrentTransform : Transforms)
{
 //Do Stuff by using CurrentTransform
}
1 Like

I have fixed Transforms and later when I get them they are randomized

.


.

The key question is why you cannot guarantee the uniqueness of the locations at the generation stage? (you take it from meshes, but at some point before you need to set it to that meshes)

Guaranteeing uniqueness during creation would simplify the entire process as much as possible, because it would be enough to
1.) grab locations
2.) shuffle
3.) just assign one by one to items

locations are itself unique, the containers transforms are itself unique.
I already takes a unique Location from the array of random range
Location = Available[FMath::RandRange(1, Available.Num() - 1)];
UsedLocations.Add(Location) // used for future checks if to know the location is used and can’t be duplicated
SpawnLocation = Location

the next time it loops it make new random range by -1 if duplicated range, repeat randomizing.
as you can see everytime the mesh should take a new unique location to be spawned.

in blueprint the logic works becuase comparing memory behind the scene to unique address , but in C++ the loop goes just infinite and the engine freeze.

in unreal C++ FTransform don’t have a find function like in blueprint , I can’t make UsedLocations.find(Location) == -1 this is the main problem of the issue, I don’t know why the dev’s missed it… I don’t know how to overload my own method operator somehow

Why not just remove used location?

auto RandomIndex = FMath::RandRange(1, Available.Num() - 1);
Location = Available[RandomIndex];
Available.RemoveAt(RandomIndex);

RemoveAt function will remove duplicates?

this is my algorithm for generating items.

You say locations are itself unique, the containers transforms are itself unique.

If you remove something from array then you can’t hit it next time.