UCLASS()
class MYMOD_API AMyActor : public AActor
{
GENERATED_BODY()
public:
AMyActor();
public:
UPROPERTY(VisibleAnywhere, Category = "Components")
USceneComponent* SceneRootComponent = nullptr;
};
AMyActor::AMyActor()
{
SceneRootComponent = CreateDefaultSubobject<USceneComponent>("My Scene Component");
SetRootComponent(SceneRootComponent);
}
and drop it into a level in the editor, it works and “My Scene Component” shows up as the root component in the details panel.
If I modify it to:
UCLASS()
class MYMOD_API AMyActor : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AMyActor();
public:
UPROPERTY(VisibleAnywhere, Category = "Components")
UPrimitiveComponent* SceneRootComponent = nullptr;
};
AMyActor::AMyActor()
{
SceneRootComponent = CreateDefaultSubobject<UPrimitiveComponent>("My Scene Component");
SetRootComponent(SceneRootComponent);
}
It no longer works, and the “My Scene Component” no longer shows up in the details panel when dropped into the editor.
Is this supposed to work? Can an actor have a root component that is a subclass of USceneComponent, or does the root component have to exactly a USceneComponent?
If it is supposed to work, why isn’t this code working?
You can use any derivative of USceneComponent as the RootComponent - but a few notes:
Don’t Hot-Reload or use Live Coding when changing this. Close the editor and relaunch.
If you change the the property type (e.g, Scene->Primitive) and already created a Blueprint, the old blueprint will be broken. You will need to recreate it, or you need to change the variable name and resave it. Making breaking changes to constructors once a Blueprint has been serialized can cause problems.
It’s not advisable to use use spaces in UObject/FName names.
As you suggested I tried creating a C++ Actor with a UPrimitiveComponent as the root as shown in second example:
With the editor closed
No spaces in the name
then compiled and launched editor. I then created a completely new blueprint class derived from the actor.
It still doesn’t work. The root component shows up as DefaultSceneComponent, and not the UPrimitiveComponent.
Why don’t you try and reproduce the problem. Try creating a C++ Actor with a UPrimitiveComponent as the root component and then derive a blueprint class from it.
The problem seems particular to UPrimitiveComponent. If I use some other component derived from UPrimitiveComponent as the root component, it works (for example UStaticMeshComponent).
The issue is that you’re trying to instantiate an actual UPrimitiveComponent as the root - which is abstract (by design) and cannot be instanced for this reason. I’m surprised you’re not seeing any warnings in the logs or triggering an ensure when creating the blueprint/during load.
You can keep a pointer to a UPrimitiveComponent as the root, but the actual component you create has to be a non-abstract type.
I found it suprising that there was no error message too. How do you know that UPrimitiveComponent is abstract - whereas (for example) UStaticMeshComponent is not? ie How can you tell the difference between an abstract class and a concrete one? (It’s not abstract in the true C++ sense of having a pure virtual function)
Ah no, it’s abstract in “Unreals” sense. If you peek at the header, you can see that the UCLASS() macro contains the Abstract markup.
Essentially you can instance them but it’ll throw a warning when you do. Maybe the default subobject code doesn’t do that for a reason but I’m not sure, if you try to do it at runtime in other cases it usually warns you and fails.