Conditionally Create Components in Constructor

I want my BaseItem classes to support either a static mesh or skeletal mesh, and I don’t want to create 2 separate components if only one is going to be used. I’ve set up some properties in an attempt to support that:

	UPROPERTY(EditAnywhere, Category = "Mesh")
	bool bUseSkeletalMesh;

	UPROPERTY(EditAnywhere, Category = "Mesh", meta=(EditCondition="bUseSkeletalMesh"))
	USkeletalMeshComponent* m_skeletalMeshComp;
	UPROPERTY(EditAnywhere, Category = "Mesh", meta=(EditCondition="!bUseSkeletalMesh"))
	UStaticMeshComponent* m_staticMeshComp;

And in the constructor:

if (!bUseSkeletalMesh)
	m_staticMeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMesh"));
	RootComponent = m_staticMeshComp;
	m_skeletalMeshComp = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("SkelMesh"));
	RootComponent = m_skeletalMeshComp;

First of all, in order for this to work after recompiling, I had to cache off any changed values (such as bUseSkeletalMesh) to a static editor object, since those get wiped during the recompile, then retrieve and set them in the constructor. I also set up the new component objects in PostEditChangeProperty, in response to the bUseSkeletalMesh property being changed:

	FName memberName = PropertyChangedEvent.GetPropertyName();
	if (memberName == GET_MEMBER_NAME_CHECKED(AUSCreatable, bUseSkeletalMesh))
		if (bUseSkeletalMesh)
			StaticMeshComp = nullptr;
			SkeletalMeshComp = NewObject<USkeletalMeshComponent>(this, TEXT("SkeletalMesh"));
			SkeletalMeshComp = nullptr;
			StaticMeshComp = NewObject<UStaticMeshComponent>(this, TEXT("StaticMesh"));

		m_boxComp->AttachToComponent(RootComponent, FAttachmentTransformRules::SnapToTargetNotIncludingScale);

What I’m seeing is that while I’m in the editor, I check UseSkeletalMesh, the component gets properly created by the above code. I then set the static mesh in the component to a mesh, compile it, save it, and all is well.

THE PROBLEM: when I reload the editor, both the static and skeletal mesh components are null, as if no data for either was serialized/deserialized. I’m assuming I’m missing some registration call or something to make sure these NewObject-created components get serialized properly, but I’m not sure…

1 Like

There might be issue doing conditional things in constructor or else it is something like build information that does not change. Constructor is used to generate CDO with is countasins default values and it’s only generated in engine init and constructor data gonna be generated only on that moment, there mightfearther problem as blueprint dupicate and override that CDO to child blueprints. So yea constructor is not good place to do dynamic or conditional thigns in constructor.

If you want to do thins kind of things, constructor is best place, also you can init both component and enable only one depending on bool state. But i think better would be if oyu made base class with common stuff and two child classes for static and skeletal mesh, which would also help you handle both differently

Yeah, ideally I’d be able to separate this into two classes, one for static, one for skeletal. But that’s a nightmare to maintain, as I’d have to maintain two different branches of child classes, when all the logic except for the mesh would be nearly identical.

I’ve thought about maybe pushing the item logic into a component, but man it would be nice to just have it setup so any child could choose static or skeletal mesh and all the item logic is just in the actor.

I had a bit of a hard time following your second part there, what did you mean when you said

“If you want to do thins kind of things, constructor is best place, also you can init both component and enable only one depending on bool state.”

I assume you meant something other than “constructor”?