AddUnique || TArray<FTransform>?

How to add unique elements from FTransform Arrray to another FTransform Array?

TArray<FTransform> Available;
TArray<FTransform> UniqueArr;
FTransform& Location = GetRandomLocation(Available);
UniqueArr.AddUnique(Location);
FTransform& AMyGameMode::GetRandomLocation(TArray<FTransform>& Location)
{
	return Location[FMath::RandRange(0, Location.Num() - 1)];
}

ERROR:: Binary “==” No operator found

Hi @Alexa.Ki !

There are a few things that are weird in the code you sent, I’m not sure you are using the Ampersand & correctly, what it does is use the value of the reference and if it is edited, it edits the reference. And it is usually used for functions that return or change more than one value.

What I would try is to remove all ampersands from the GetRandomLocation, so it ends up something like this:

FTransform AMyGameMode::GetRandomLocation(const TArray<FTransform> Locations)
{
	return Location[FMath::RandRange(0, Location.Num() - 1)];
}

I added a const too, which means that the variable Locations won’t be modified on the function, as it is only getting one random value from that array, it is correct that it won’t alter the array of locations.

Then I would change these

To this:

FTransform Location = GetRandomLocation(Available);
UniqueArr.AddUnique(Location);

For Tarrays, you can also call the .Add(), so it ends up as UniqueArr.Add(Location)

As for this

The error doesn’t match with what you uploaded, so maybe it’s somewhere else.

1 Like

Thank you Sir for replying and correcting my code according to you.
But the error: ERROR:: Binary “==” No operator found is ralated to the code because while adding the FTransform values are checked for == or != to compare before adding a unique value because the operator == is not available for Comparing Transforms.

I can show an example: FTransform Comparison Issue
This is related to this Issue and I have a solution on this post for this issue but it freez the engine.

Now I understand what the problem was, the ampersand part is true btw :sweat_smile:

All right, then to solve that problem you have a few options:

  1. Edit the file FTransform on the engine and add the == and != operators directly to that struct. (This could be troublesome if you can’t edit the engine).

  2. Create another array of FTransforms named something like NotUniqueLocations and add every location to that array, then create a function that checks if that array has unique transforms, declaring that they are equal if their scale, location, and rotations are the same. With that function you could clean up that array of all the data and then retrieve the unique locations into the UniqueArr array (You would need to do this each time you know they could be different, like at the end of when that code is run)

  3. Another idea would be to check if the array already has that transform with the Contains method:

if (!UniqueArr.Contains(Location))
{
    UniqueArr.Add(Location)
}

Although I’m not sure if you can use Contains on a thing that is not an UObject

  1. Make your custom ContainsTransform method something like this:
bool ContainsTransform(TArray<FTransform> TransformArray, FTransform Transform)
{
    for (FTransform Trans : TransformArray)
    {
         if (Trans.GetScale3D() == Transform.GetScale3D() && 
             Trans.GetLocation() == Transform.GetLocation() && 
             Trans.GetRotation() == Transform.GetRotation())
         {
              return true;
         }
    }
    return false;
} 

And then you call it like the above method:

if (!ContainsTransform(UniqueArr, Location))
{
    UniqueArr.Add(Location)
}
1 Like

I would like to do this but it will not need to re-build the engine?

You can use TSet.

struct KeyFuncsForTransform : public DefaultKeyFuncs<FTransform, false> 
{
  static bool Matches(KeyInitType Left, KeyInitType Right)
  {
    return Left.Equals(Right, 0.001);
  }
  static uint32 GetKeyHash(KeyInitType Key)
  {
    return GetTypeHash(Key.GetTranslation());
  }
};

Usage:

using UniqueTransformSet = TSet<FTransform, KeyFuncsForTransform>;

void Example()
{
  auto UniquesOnly = UniqueTransformSet{};
  for (auto i = 0; i < 10; ++i) {
    UniquesOnly.Add(FTransform::Identity);
  }
  UE_LOG(LogTemp, Warning, TEXT("%i"), UniquesOnly.Num()); // print `1`
1 Like

Can i use this instead of do/while loop which is freezing the engine? Issue Link i posted mygamemode please check what i a doing wrong in the code

That’s right, you would need to compile it again (that takes roughly 45 min - 2 hours depending on your PC)

1 Like