Unreal Engine: How can I create UStaticMeshComponent in a loop?

I am trying to create multiple UStaticMeshComponent by using for loop but Unreal Engine keeps triggering breakpoint on CreateDefaultSubobject in Object.h(Not in my code, it's from UE4 core API). When I'm creating a single component it's working fine. I am pretty new to UnrealEngine and C++ so I might be doing something dumb but please be easy on that:)

Thank you so much for your help.

Header

#pragma once #include "CoreMinimal.h" #include "GameFramework/Actor.h" #include "FlowSphere.generated.h" UCLASS() class CPP_PRACTICE_3_API AFlowSphere : public AActor { GENERATED_BODY() public: // Sets default values for this actor's properties AFlowSphere(); protected: // Called when the game starts or when spawned virtual void BeginPlay() override; public: // Called every frame virtual void Tick(float DeltaTime) override; private: //UPROPERTY() //TArray<UStaticMeshComponent*> StaticMeshComponents; UStaticMeshComponent* test; }; 

C++

#include "FlowSphere.h" // Sets default values AFlowSphere::AFlowSphere() { int32 amount = 100; RootComponent = CreateDefaultSubobject<USceneComponent>("SceneComponent"); for (int32 i = 0; i < amount; i++) { //WHEN I INCLUDE THE LINE BELOW, UE4 START MAKING BREAKPOINT UStaticMeshComponent* item = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Sphere")); item.AttachTo(this->RootComponent); } //THIS WORKS FINE this->test = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("HELLO")); PrimaryActorTick.bCanEverTick = true; } // Called when the game starts or when spawned void AFlowSphere::BeginPlay() { Super::BeginPlay(); } // Called every frame void AFlowSphere::Tick(float DeltaTime) { Super::Tick(DeltaTime); } 

Where it triggering breakpoint on the Object.h from UE4 API

 /** * Create a component or subobject * @param TReturnType class of return type, all overrides must be of this type * @param SubobjectName name of the new component * @param bTransient true if the component is being assigned to a transient property. This does not make the component itself transient, but does stop it from inheriting parent defaults */ template<class TReturnType> TReturnType* CreateDefaultSubobject(FName SubobjectName, bool bTransient = false) { UClass* ReturnType = TReturnType::StaticClass(); return static_cast<TReturnType*>(CreateDefaultSubobject(SubobjectName, ReturnType, ReturnType, /*bIsRequired =*/ true, /*bIsAbstract =*/ false, bTransient)); } 

2 Answers

You used the same name for two different calls to CreateDefaultSubobject.

I ran your code in a new UE4 C++ project and got the following error message:

Fatal error: [File:D:\Build++UE4\Sync\Engine\Source\Runtime\CoreUObject\Private\UObject\UObjectGlobals.cpp] [Line: 3755] Default subobject StaticMeshComponent Sphere already exists for FlowSphere /Script/MyProject.Default__FlowSphere.

Also, the code you posted didn't compile.

item.AttachTo(this->RootComponent); 

should have been:

item->AttachTo(this->RootComponent); 

and you also needed to include "Components/StaticMeshComponent.h". Here is the corrected code:

#include "FlowSphere.h" #include "Components/StaticMeshComponent.h" // Sets default values AFlowSphere::AFlowSphere() { int32 amount = 100; RootComponent = CreateDefaultSubobject<USceneComponent>("SceneComponent"); for (int32 i = 0; i < amount; i++) { FName name = *FString::Printf(TEXT("Sphere %i"), i); UStaticMeshComponent* item = CreateDefaultSubobject<UStaticMeshComponent>(name); item->AttachTo(this->RootComponent); } this->test = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("HELLO")); PrimaryActorTick.bCanEverTick = true; } 

So I had to do the same thing recently and ran into a lot of issues but the two major things to fix are:

  1. use UInstancedStaticMesh instead of UStaticMesh.
  2. add a property to your static mesh.

Below is the correct code.

#include "FlowSphere.h" #include "Components/StaticMeshComponent.h" #include "UObject/ConstructorHelpers.h" // Sets default values AFlowSphere::AFlowSphere() { int32 amount = 100; RootComponent = CreateDefaultSubobject<USceneComponent>("SceneComponent"); for (int32 i = 0; i < amount; i++) { FName name = *FString::Printf(TEXT("Sphere %i"), i); FName c_name = *FString::Printf(TEXT("ChildSceneComponent %i"), i); UPROPERTY(EditAnywhere) USceneComponent* ChildSceneComponent = CreateDefaultSubobject<USceneComponent>(c_name); // instead of the regular static mesh, create and instance static mesh object with name assigned UInstancedStaticMeshComponent* item = CreateDefaultSubobject<UStaticMeshComponent>(name); item->RegisterComponent(); // assign property to mesh if not you'll get a static mesh null property error like i did auto MeshAsset = ConstructorHelpers::FObjectFinder<UStaticMesh>(TEXT("StaticMesh'/Engine/BasicShapes/Sphere.Sphere'")); if (MeshAsset.Object != nullptr) { item->SetStaticMesh(MeshAsset.Object); } item->SetFlags(RF_Transactional); // add instance to actor level this->AddInstanceComponent(item); // make the scene component for the mesh to be visible RootComponent = Root; // attach mesh to the scene component of the actor in form of a Hierarchy item->AttachToComponent(ChildSceneComponent, FAttachmentTransformRules::KeepWorldTransform, m_name); ChildSceneComponent->AttachToComponent(Root, FAttachmentTransformRules::KeepWorldTransform, c_name); // set mesh transform based on the ith position FTransform t(FVector(250 * i, i, i)); // activate the new copy of the mesh Mesh->AddInstance(t); // Offset and scale the child scene from the root scene as a precaution ChildSceneComponent->SetRelativeTransform( FTransform(FRotator(0, 0, 0), FVector(250 * i, i, i), FVector(0.1f)) ); } PrimaryActorTick.bCanEverTick = true; } 

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

You Might Also Like