I'm trying to create a SphereComponent dynamically 2 seconds after the level is started. For that I have this following code:
void ACollidingPawnSpawnPawns::DelayedFunction() {
// The first parameter 'SphereComponent' is the main component in the level and it has been created using the CreateDefaultSubobject method in the constructor of this class. But that method can't be used outside the constructor.
USphereComponent *dynamicallyCreatedSphere = NewObject<USphereComponent>(SphereComponent, USphereComponent::StaticClass());
dynamicallyCreatedSphere ->InitSphereRadius(30.0f);
dynamicallyCreatedSphere ->SetCollisionProfileName(TEXT("Pawn"));
dynamicallyCreatedSphere ->SetRelativeLocation(FVector(155.0f, 165.0f, 45.0f));
dynamicallyCreatedSphere ->SetVisibility(true);
}
After I run the level I don't see this dynamic sphere pop up.
For the main 'SphereComponent' that does show up this code is in the constructor:
// Our root component will be a sphere that reacts to physics
SphereComponent = CreateDefaultSubobject<USphereComponent>(TEXT("RootComponent"));
RootComponent = SphereComponent;
SphereComponent->InitSphereRadius(40.0f);
SphereComponent->SetCollisionProfileName(TEXT("Pawn"));
// Create and position a mesh component so we can see where our sphere is
UStaticMeshComponent* SphereVisual = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("VisualRepresentation"));
SphereVisual->SetupAttachment(RootComponent);
static ConstructorHelpers::FObjectFinder<UStaticMesh> SphereVisualAsset(TEXT("/Game/StarterContent/Shapes/Shape_Sphere.Shape_Sphere"));
if (SphereVisualAsset.Succeeded())
{
SphereVisual->SetStaticMesh(SphereVisualAsset.Object);
SphereVisual->SetRelativeLocation(FVector(0.0f, 0.0f, -40.0f));
SphereVisual->SetWorldScale3D(FVector(0.8f));
}
But again I can't use the CreateDefaultSubobject to create the UStaticMeshComponent outside the constructor.
So I imagine for me to see my dynamicallyCreatedSphere in my level I would have to create a UStaticMeshComponentand I would need some variation of the FObjectFinder method to invoke (this FObjectFinder also doesn't work outside the constructor).
I've been stuck on this for a while now. Anyone know how to do this?
Update 2021-12-2 Thanks to advice from https://stackoverflow.com/a/70180682/4722577 below, here's the final code I have to create the sphere dynamically:
In the cpp file:
void ACollidingPawnSpawnPawns::spawnPawns()
{
if (dynamicallyCreatedSphere == nullptr) {
//dynamicallyCreatedSphere = NewObject<USphereComponent>(USphereComponent::StaticClass()); // compiles
dynamicallyCreatedSphere = NewObject<USphereComponent>(SphereComponent, USphereComponent::StaticClass());
//dynamicallyCreatedSphere->SetupAttachment(SphereComponent);
dynamicallyCreatedSphere->InitSphereRadius(30.0f);
dynamicallyCreatedSphere->SetCollisionProfileName(TEXT("Pawn"));
dynamicallyCreatedSphere->SetRelativeLocation(FVector(155.0f, 165.0f, 45.0f));
dynamicallyCreatedSphere->SetVisibility(true);
dynamicMesh = NewObject<UStaticMeshComponent>(this);
dynamicMesh->AttachToComponent(dynamicallyCreatedSphere, FAttachmentTransformRules::KeepWorldTransform);
dynamicMesh->RegisterComponent();
dynamicMesh->SetStaticMesh(StaticMesh);
}
}
in the .h file I have these 3 lines:
UPROPERTY(EditAnywhere)
UStaticMesh* StaticMesh;
USphereComponent* dynamicallyCreatedSphere = nullptr;
UStaticMeshComponent* dynamicMesh = nullptr;
Declaring the StaticMesh as a UProperty allows me to select the mesh manually in the UE interface. Then when I run the level that StaticMesh is inserted into the dynamicMesh variable.
First, only NewObject
can be used to create components outside of constructor:
void ACollidingPawnSpawnPawns::DelayedFunction()
{
// you should specify outer as current actor (because this component is part of it)
USphereComponent* DynamicallyCreatedSphere = NewObject<USphereComponent>(this, USphereComponent::StaticClass());
DynamicallyCreatedSphere->RegisterComponent();
// when component is dynamically created, you can use AttachToComponent, not SetupAttachment
DynamicallyCreatedSphere->AttachToComponent(GetRootComponent(), FAttachmentTransformRules::KeepRelativeTransform);
DynamicallyCreatedSphere->InitSphereRadius(30.0f);
DynamicallyCreatedSphere->SetCollisionProfileName(TEXT("Pawn"));
DynamicallyCreatedSphere->SetRelativeLocation(FVector(155.0f, 165.0f, 45.0f));
DynamicallyCreatedSphere->SetVisibility(true);
}
Instead of FObjectFinder
you can use LoadObject
to load something using specified path. But I think this is incovinent way, because ref is hardcoded.
Use following code in UCLASS instead:
UPROPERTY(EditAnywhere)
UStaticMesh* StaticMesh;
And specify static mesh directly: SphereVisual->SetStaticMesh(StaticMesh);
After that you can inherit C++ class to blueprint and pick StaticMesh from Content Browser.