Setting a static mesh's asset based on a blueprint-exposed property

Hello! I would like to create an object that could have a variety of possible meshes, based on level-design. The idea is that I will create a number of blueprints that inherit from this C++ class, and have the mesh exposed as a property. With that in mind:

.h file

UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = Mesh)
UStaticMesh* MeshAsset;

.cpp file, (in constructor)

MeshComponent = CreateDefaultSubobject< UStaticMeshComponent >(TEXT("StaticMeshComponent"));
RootComponent = MeshComponent;
MeshComponent->SetRelativeLocation(FVector(0.0f, 0.0f, 0.0f));
MeshComponent->SetWorldScale3D(FVector(1.f));
if (MeshAsset)
{
	MeshComponent->SetStaticMesh(MeshAsset);
}

However, the actor’s static mesh is not being assigned to the blueprint-specified mesh. I’ve managed to get the mesh working if I hard-code it in… Is this because I’m doing this in the constructor? Have I missed something really obvious?

You need to override OnConstruction in your actor and move your mesh assignment code there. It’s a bit confusing but the constructor of the actor only gets called when it’s initialized and thus has no level or editor details panel data assigned to it. If you set it in the OnConstruction method you will see the changes in the editor but not if you change it programmatically in the level blueprint, for that you need to use beginplay.

I had the same problem and I got it to work with the OnConstruction method.

So your .h file should look something like that:

/**called when object is placed in editor or spawned in world*/
virtual void OnConstruction(const FTransform& Transform) override;
    
/**Static mesh component*/
UStaticMeshComponent* MeshComponent;
    
/**Static mesh (changeable in the editor)*/
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Mesh")
UStaticMesh* DisplayMesh

And your .cpp file should look something like this:

AMyActor::AMyActor()
{    
	MeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("RootMeshComponent"));
	RootComponent = MeshComponent;
}

void AMyActor::OnConstruction(const FTransform& Transform)
{
	Super::OnConstruction(Transform); //Don't forget the Super call!
	MeshComponent->SetStaticMesh(DisplayMesh);
}

If you also want to make sure that programmatic changes are handled, add the necessary code to the BeginPlay method.

Warning!!! Do NOT call the “CreateDefaultSubobject” function inside “OnConstruct”! It will crash your project!

Edit:
If you need to create the Components inside the OnConstruct function, do this:

void AMyActor::OnConstruction(const FTransform& Transform)
{
	Super::OnConstruction(Transform);
	MeshComponent = NewObject<UStaticMeshComponent>(this, TEXT("RootComponent"));
	MeshComponent->SetStaticMesh(DisplayMesh);
	MeshComponent->AttachTo(RootComponent); //(or whatever component you want it to attach to...)
	MeshComponent->RegisterComponent(); //VERY IMPORTANT if you want it to show up inside the editor!!!
}

Works fabulously, thank you for your very thorough response!! I very much appreciate it.

Your are very welcome :wink: