Download

C++/BP Instantiate dynamic components when properties change

Hey,

So I stumbled upon this curious scenario. I got an Actor that I need to set values for in the blueprint editor. They are usually descriptors that will determine things like the mesh or animation the actor will display. Naturally I was tempted to implement something that would show me live feedback for this process - this means creating the mesh component and play animations live.

My first attempt was something like so:

MyActor::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
{
    // Check if relevant property change
    UpdatePreview();
}

MyActor::UpdatePreview()
{
    for(int i = 0; i < numPreviewActors; ++i)
    {
        if(!m_previewMeshes[i])
        {
              m_previewMeshes[i] = AddComponentByClass(USkeletalMeshComponent::StaticClass, ...);
        }

        m_previewMeshes[i]->SetMesh( ... ) // etc.
    }
}

The first problem I ran into is that AddComponentByClass will assert, because the World will always be tearing down around the time the property changes. Not sure why…but I did readings on the ConstructionScript, and realized it may be more appropriate. When I moved that logic to the ConstructionScript, I ended up with TRASH components in the array, so I didn’t get the preview I was expecting.

After some readings, I am inclined to say this is an intended consequence as ConstructionScripts can get disastrous when spawning things.

The ultimate hacky approach that worked for me is to create an fixed, arbitrarily large number of skeletal mesh components in advance (in the constructor), then proceed to only SET the skeletal mesh reference when I do the preview update.

This leaves me wondering if there are any approaches to getting something that resembles a live preview working. Note, this is in the context of the Blueprint Editor, not the level editor! I am aware there are ways to do it for actors instanced in the level … but how about the Blueprint Editor?

Also, I plan on extending this to spawning actual actors - it was a hit or miss when I first tried it, again, mainly because the World pointer will be null from time to time.

Perhaps make the properties replicated, and do the work in OnRep() ?

I kinda feel like that may be more hacky than what I currently have - would it even work in editor without multiplayer configured?

Also an update: I am not quite sure what changed… I am tidying up my code a bit, and all of the sudden, my attempts at playing an animation on the mesh no longer works. It 100% worked at one point, and I expect it to because this is already a built in feature when you select an animation asset to play here:

image

I tried playing the animation both in the ConstructionScript and PostEditChangeProperty - neither work. The snippet is simply:

previewMesh->SetAnimationMode(EAnimationMode::AnimationSingleNode)
previewMesh->SetAnimation( montage.LoadSynchronous());
previewMesh->Play(true);

or

previewMesh->PlayAnimation(montage.LoadSynchronous(), true); // Does exactly the above

There must be some gimmick I am overlooking with things not ticking or updating when I expect them to in the Blueprint editor. The mesh and animation assets are all valid.

Alright, I got the latter problem working after realizing calling PlayAnimation from the construction script is a special case, which the engine was nice enough to provide a workaround for via:

previewMesh->OverrideAnimationData(montage, true, true);

So now we’re back to the original question of: how do we avoid this workaround of pre-allocating a static number of components. Ideally, I’d want to conditionally create these preview meshes whenever a specific property change - so I promise it won’t be spammy or crash-inducing.