If I create a simple hierarchy like this ActorA->ComponentB->ComponentC->StaticMesh;
The creation of all objects are by default in the constructor using the initialisers CreateDefaultSubObject for each type.
I create a BP instance of ActorA and add to the world.
In play, the static mesh component can be seen both in the object details, and in the scene.
Move the creation of the Actor to a beingPlay call using NewObject, the actor appears in the scene, the nodes are visible in the object details including the StaticMesh.
But the static mesh is not visible, changnig details moving the actor have no effect.
All components are using RegisterComponent() after creation during runtime.
After I’ve bumped into this issue a few times now, I’ve decided to spend some time investigating the bug. I’ll add my findings here, since this post is often found on Google when searching “NewObject invisible”.
Your statement is correct:
CreateDefaultSubObject() is used in the constructor.
NewObject() and RegisterComponent() are used at runtime.
However there are situations where this isn’t sufficient:
Assume you use NewObject() at runtime to create ObjectOne.
ObjectOne creates ObjectTwo in the constructor (by using CreateDefaultSubObject()).
In this situation ObjectOne has to call ObjectTwo->RegisterComponent() manually at runtime. (e.g. OnBegin)
I suppose this is due to ObjectOne not being registered itself while the constructor executes. It probably skips the registration of it’s components.
This code works for creating arbitray static mesh attachment hierarchies at runtime:
code is called in the Actor
you can attach the new component to RootComponent
or some other component
you’ll need a (1) a unique component name within the actor, (2) a socket name to attach to, and (3) a reference to the UStaticMesh you want the new component to use
// create new component, set mesh, and attach
UStaticMeshComponent* newComponent = NewObject<UStaticMeshComponent>(this, "NewComponentName");
newComponent->AttachToComponent(RootComponent, FAttachmentTransformRules::SnapToTargetIncludingScale, "AttachSocketName");
newComponent->SetStaticMesh(staticMeshReference);
newComponent->RegisterComponent();