I know there is the usual route of doing all of the C++ component construction with “PCIP.CreateDefaultSubObject”,
But I want to dynamically create mesh components in the editor.
E.G.: I move a transform, and it calculates how many meshes should be between the world position and the transform position, etc.
I know how to handle the array of sub-object pointers, and I know I can use the “OnCustruction” function to replicate the Construction Graph,
but what I can’t seem to find, is the C++ equivalent of Blueprint’s “Add StaticMeshComponent”
How should I go about doing this? Or should I just do that part in the BP Construction Graph? (I’d prefer not to)
I like to do as much as possible in C++. Even when I find defaults that suit the custom BP, I tend to save them in the Script,
meaning as long as I have my source backed up, I can lose the ENTIRE project, and not have much to do (Except importing, and Animations, etc)
I really wish this was better documented, because our team spent well over a month trying different variations on this trying to get it to work. I’m also not sure if this is the “correct” way to go about this, but it does seem to work pretty well.
(Side note: you don’t actually have to store references to your created meshes if you don’t need them, as they’re stored for you when you register them. We needed to be able to get references to specific meshes in the order we created them, so the TArray was really important for us.)
.h file:
UCLASS()
class ASomeActor : public AActor
{
GENERATED_UCLASS_BODY()
virtual void OnConstruction(const FTransform& transform) override;
public:
/** Root component */
UPROPERTY()
TSubobjectPtr<USceneComponent> Root;
/** Static mesh to create */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Some Actor")
UStaticMesh* SomeMesh;
protected:
/** Storage for all mesh components */
UPROPERTY(Transient)
TArray<UStaticMeshComponent *> Meshes;
};
.cpp file:
ASomeActor::ASomeActor(const class FPostConstructInitializeProperties& PCIP)
: Super(PCIP)
{
Root = PCIP.CreateAbstractDefaultSubobject<USceneComponent>(this, TEXT("Root"));
RootComponent = Root;
Meshes = TArray<UStaticMeshComponent *>();
}
void ASomeActor::OnConstruction(const FTransform& transform) {
Super::OnConstruction(transform);
// clear out any references to the old set of meshes
Meshes.Empty();
// create the static mesh component
UStaticMeshComponent* mesh = NewObject<UStaticMeshComponent>(this);
mesh->AttachTo(RootComponent);
mesh->RegisterComponent();
// required for proper GC - this causes the mesh to get automatically destroyed when OnConstruction is re-run
mesh->bCreatedByConstructionScript = true;
// keep our own reference to the mesh
Meshes.Add(mesh);
// now you can do whatever setup you need to do
mesh->SetStaticMesh(SomeMesh);
mesh->SetWorldLocation(GetActorLocation());
}
C++ does have a construct function that is called automatically, either on creation or on drag/moving the actor.
Both myself and **JuddC **listed it above
To use it, create the public header as usual and then in the private class:
void AMyCustomActor::OnConstruction::OnConstruction(const FTransform& transform)
{
Super::OnConstruction(transform);
//Insert all your useful code here!
}
Note: This is completely separate from the normal constructor function in each class.
Actually I had some issues with the construction script sometimes not re-running when the actor is dragged. There’s a checkbox in blueprints to do this, but I couldn’t find a better way to do this in C++. There’s probably a better way to solve this, but this works pretty well:
I’ve actually never experienced this before.
Except for whenever I undo a movement, etc, which is understandable.
Although in terms of forcing the construction, your method is the best I’ve seen so far.
Otherwise you’d have to grab a pointer array of all blueprint classes required to instantiate your class,
and then force ‘bRunConstructionScriptOnDrag’ to true.