NewObject from TArray(TSubclassOf(UMyComponent))

Excuse the parentheses, the forum is removing pointed brackets.

If I have a TArray filled with TSubclassOf(UMyComponent) where UMyComponent is a subclass of StaticMeshComponent, what’s the best way to use NewObject to create a component from that array entry?

I just want to take the TArray, give it an index on the fly, grab the TSubclassOf from that index, and hand it to another Actor to create a component from. The problem is NewObject wants an object pointer, and all I’ve got is a class pointer, and it says *UMyComponent is not compatible with TSubclassOf(UMyComponent)

Any suggestions? It’s doing my head in, and I’m sure it’s just because I’m not grasping the system. Thanks in advance for any insight you can offer.

Can you post a snippet of the code? Difficult to say what you’re doing wrong without seeing it.

No worries. I wrote up a huge post with snippets and screenshots but the forum wiped it :frowning:

So it’s basically a TArray filled with “track pieces” (UPiece)

A struct of TArray and Name:

USTRUCT(BlueprintType) struct FPiecesStruct {
	GENERATED_USTRUCT_BODY()
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	FString Name;
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	TArray<class UPiece*> ArrayOfPieces;
};

This is created as an Array variable in BP so I can have multiple TArrays, and then filled with my component UPiece (subclass of UStaticMeshComponent)

One of these Arrays is passed into the Intialise() BP node. When the method is called, I want it to pick out the UPiece entry from the TArray based on whichever Index it’s been given:

	UPiece* NextPiece = MyPiecesSet.ArrayOfPieces[PiecesArrayInt[Index]];

Then I want to pass that to an Actor in the scene:

	MyTrack->ArrangeNextPiece(NextPiece);

And that Actor should add it as a component:

void ATrack::ArrangeNextPiece(UPiece* NextPiece)
{
	FName Name = FName();
	UPiece* CurrentPiece = NewObject<UPiece>(this, Name, RF_NoFlags, NextPiece, false, nullptr);

	CurrentPiece->SetWorldLocation(NextPieceLocation, false, 0, ETeleportType::None);
	NextPieceLocation = CurrentPiece->GetSocketLocation(FName("Socket"));

	CurrentPiece->SetWorldRotation(NextPieceRotation, false, 0, ETeleportType::None);
	NextPieceRotation = CurrentPiece->GetSocketQuaternion(FName("Socket"));
}

This code hard-crashes on Play. I’m sure I’m just fundamentally misunderstanding the classes/pointers/etc.

The STRUCT used to be:

TArray<TSubclassOf<UPiece>> ArrayOfPieces;

But I’ve been playing with it. Neither works.

That is what it should be and ArrangeNextPiece should take in a TSubclassOf.

void ATrack::ArrangeNextPiece(TSubclassOf<class UPiece> NextPiece)

Thank you very much. I’m still struggling with how to use that argument in ArrangeNextPiece() to add it as a component to ATrack. I’ve got:

void ATrack::ArrangeNextPiece(TSubclassOf<class UPiece> NextPiece)
{
	UPiece* CurrentPiece = NewObject<UPiece>(this, NextPiece);
}

And it hard-crashes on Play. Does that look legit?

Double check that NextPiece isn’t null. If it isn’t a valid pointer I do believe that NewObject will cause a crash.

Thanks, I should have been doing pointer protection. I have to go to work but will revisit this as soon as I get home.

No joy. I don’t understand what I’m doing wrong…

void ATrack::ArrangeNextPiece(TSubclassOf<class UPiece> NextPiece)
{
	auto CurrentPiece = NextPiece;
	FString CurrentPieceName = CurrentPiece->GetName();
	UE_LOG(LogTemp, Warning, TEXT("CurrentPieceName: %s"), *CurrentPieceName)
// UPiece* MyTrackPiece = NewObject<UPiece>(this, CurrentPiece);
}

Produces:

253084-capture.png

But then this will hard-crash the editor:

void ATrack::ArrangeNextPiece(TSubclassOf<class UPiece> NextPiece)
{
	auto CurrentPiece = NextPiece;
	FString CurrentPieceName = CurrentPiece->GetName();
	UE_LOG(LogTemp, Warning, TEXT("CurrentPieceName: %s"), *CurrentPieceName)
	UPiece* MyTrackPiece = NewObject<UPiece>(this, CurrentPiece);
}

UPiece is simply a C++ Class derived from StaticMeshComponent. I’m so confused.

So if I get rid of the “this” in the NewObject, it doesn’t crash, but the object doesn’t appear in the world nor the heirachy:

void ATrack::ArrangeNextPiece(TSubclassOf<class UPiece> NextPiece)
{
	auto CurrentPiece = NextPiece;
	FString CurrentPieceName = CurrentPiece->GetName();
	UE_LOG(LogTemp, Warning, TEXT("CurrentPieceName: %s"), *CurrentPieceName)
	UPiece* MyTrackPiece = NewObject<UPiece>(CurrentPiece);

	UE_LOG(LogTemp, Warning, TEXT("MyTrackPiece: %s"), *MyTrackPiece->GetName());
}

253086-capture.png

And if I try to SetWorldLocationAndRotation() on it, then it hard-crashes again.

So it’s happy to spawn the piece as long as it’s not attached to the ATrack… Argh…

I’m going to close this and start a new question, because it’s gone to a new topic away from TArrays.