Problem
I’ve encountered multiple situations where I needed to create a custom USceneComponent
in C++ that contains other USceneComponent
-based subcomponents as part of its default structure. However, Unreal Engine does not seem to natively support this pattern in a straightforward way.
Use Case
One specific scenario involved needing a USphereComponent
that always has an attached UWidgetComponent
. While I could manually add the UWidgetComponent
in Blueprints or during runtime, this approach feels inefficient and error-prone. Ideally, I would like to define a USceneComponent
subclass in C++ that automatically initializes and maintains its own child components without requiring external setup.
Potential Reasons for Limitation
From my understanding, the reason why USceneComponent
subclasses cannot own other components may be tied to Unreal’s component serialization system. When an AActor
is constructed, its components are serialized early in the process. If a USceneComponent
were to dynamically create and register additional subcomponents after this point, they might not be properly serialized, leading to issues with saving, loading, or modifying them in the editor.
That being said, I find it hard to believe that Unreal does not have a built-in solution for this. The closest alternative appears to be UChildActorComponent
, but from what I’ve read and experienced, Child Actors can introduce additional complexity and can be difficult to manage in code.
If This Isn’t Possible, What’s the Right Approach?
If Unreal’s architecture simply doesn’t allow USceneComponent
subclasses to own their own subcomponents in a clean way, what is the best way to rethink this pattern?
- Should I instead be thinking in terms of a single
USceneComponent
that dynamically requests its dependencies from the owningAActor
? - Is it better practice to structure this as an
AActor
rather than aUSceneComponent
? - Are there Unreal-native alternatives that achieve the same modularity while avoiding issues with serialization and ownership?
Would appreciate any insights from those who have dealt with similar scenarios.
Update: Partial Solution Found
I’ve found a way to achieve the desired behavior to some extent. Here’s what I tested:
I created UTestSphereColliderComponent
, a USphereComponent
with a UWidgetComponent
as a sub-component:
UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent), Blueprintable)
class TEST_API UTestSphereColliderComponent : public USphereComponent
{
GENERATED_BODY()
public:
UTestSphereColliderComponent();
virtual void OnRegister() override;
protected:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Sub-Component")
TObjectPtr<UWidgetComponent> WidgetComponent;
};
UTestSphereColliderComponent::UTestSphereColliderComponent()
{
WidgetComponent = CreateDefaultSubobject<UWidgetComponent>("Widget Component");
WidgetComponent->SetupAttachment(this);
}
void UTestSphereColliderComponent::OnRegister()
{
Super::OnRegister();
WidgetComponent->SetupAttachment(this);
}
Observations:
- The data persists, and the
WidgetComponent
functions correctly. - However, the WidgetComponent does not appear in the Components panel in Unreal.
- It does appear in the Details panel when selecting the
UTestSphereColliderComponent
, allowing for editing.
Additionally, when UTestSphereColliderComponent
is used inside an AActor
, the expected behavior occurs—the WidgetComponent
appears correctly in the Components panel:
UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent), Blueprintable)
class TEST_API ATestActor : public AActor
{
GENERATED_BODY()
public:
ATestActor();
protected:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Components")
UTestSphereColliderComponent* TestSphereColliderComponent;
};
ATestActor::ATestActor()
{
TestSphereColliderComponent = CreateDefaultSubobject<UTestSphereColliderComponent>(TEXT("Test Sphere Collider"));
RootComponent = TestSphereColliderComponent;
}
Conclusion:
While this method allows for proper functionality and editing in the Details panel, it does not fully resolve the issue of sub-components appearing in the Components panel when used as a standalone component.
If anyone knows a way to make a standalone component’s sub-components appear in the Components panel as well, I’d love to hear your insights!