I have a ShapeComponent stored in a data asset (serialized UObject class) that I would like to attach **dynamically **to the player, eg. without making it a preexisting component of said player. The ShapeComponent is created inside the asset’s constructor with CreateDefaultSubObject().
I have tried this code:
shapeComp->AttachTo(player->GetMesh(), "LeftHand", EAttachLocation::SnapToTarget);
And its alternatives (different parameters, AttachToComponent, etc.) to no avail. I don’t want to place the component in an actor class for performance and ‘cleanliness’ purposes (as all I need is that one component). I’ve also read that the way to dynamically add previously non-existing (eg. newly created) components is to call NewObject(outer), then AttachTo(), then RegisterComponent(), but as the component I want to add already exists I don’t want to be calling NewObject() on it.
Is this even possible and what are the steps to make it work if so?
(I’ve previously asked this on the answer hub but got no responses and an abysmal amount of views so thought I’d try here.)
You can’t, and I’m not sure why you’d ever want to do that.
If the component is stored in a data asset in the content browser, it doesn’t have a valid world, a valid owner - nothing. The actor also won’t register it properly. You’ll run into an infinite amount of problems trying to do this. Assets are meant to be classes, which you then create instances of in the game.
It’s far less clean and less performant to spawn them dynamically. If you have an actor class that always needs one of these components, you should create it as part of the actors constructor as a default component.
Alright thanks, I get why it doesn’t work now. However my actor class does not always need one of those components, and may in fact have multiple of them at different locations at very specific times, which is why I want to spawn them dynamically. Is there a way to use NewObject() such that it automatically copies all the customized properties of the shape component?
Yes, NewObject can take an argument (it’s called Template or something similar) that will do exactly that. Something like this, assuming you’ve got a pointer to your asset called Shape:
NewObject< ComponentType >(Actor, Shape->GetClass(), Name, RF_NoFlags, Shape);
Depending on your situation you may also want to consider using dedicated actors to hold your shape components, which might be a nicer solution if your shapes are not player bound, might change ownership or persist over the death of the player. Components can be created dynamically by calling NewObject and then NewComp->RegisterComponent(). You can either initialize your properties with code after you spawn the shape, or create a C++ template class or a blueprint template class which you can pass as the class argument in NewObject.