Exposing UPROPERTY on ActorComponent in Actor details

Hello, we are trying to figure something out concerning ActorComponents. We are relatively new to Unreal, coming from Unity and we also have experience in various rendering frameworks. We’d like to be able to expose some variables to easily edit in the details panel of a blueprint. From looking at how blueprints work, and from seeing various examples, it seems possible to make UPROPERTYs on certain components that then show up in the details panel of the Actor that component is attached to. We’ve scoured the internet for sources on this, and it seems “as simple as” setting the right UPROPERTY accessors, but we’ve tried everything we found. The only way we’ve so far gotten it to work is by making our component a SceneComponent instead of an ActorComponent. We are probably doing something structurally wrong here, but we don’t understand what. Ideally we also wouldn’t be setting a float (floats are easy to set via code), but a full class reference (SubclassOf<AMySpawnableActor>) to the component for it to work as a spawner.

Some sources we’ve referred to are the original docs: Adding Components to an Actor in Unreal Engine | Unreal Engine 5.3 Documentation, and this old wiki page Actor Custom Components, Edit Variables Per Instance In Level Editor - Old UE4 Wiki. They seem to be doing about the same things.
Here’s a code sample

UCLASS()
class AMyClass : public AActor
{
    GENERATED_BODY()

public:
    AMyClass()
    {
        MyComponentReference = CreateDefaultSubobject<UMyComp>(TEXT("MyComponent"));
    }

    UPROPERTY(????)
    UMyComp* MyComponentReference;
};

UCLASS()
class UMyComp : public UActorComponent
{
    GENERATED_BODY()

public:
    UPROPERTY(????)
    float MyVeryCoolFloat;
};

fill it with EditAnywhere
use EditInstanceOnly if u just wanna it editable when it is being placed to the level, or
EditDefaultsOnly if u just wanna it editable when u open it on blueprint window

u can use Visible... if u want it read-only

for things that are meant to “live” for longer periods of time I would suggest a wrapper of

TObjectPtr<UMyComp> MyComponentReference;

you work with them the same as pointers, but you get added type checking, and it is less likely that Garbage Collection will run away with your object.

for what to put in the UPROPERTY macro

  • EditAnywhere: for the ability to edit it well anywhere
  • EditDefaultsOnly: this will allow you to modify it in Blueprints, but be careful with encapsulating something that has EditDefaultsOnly on its members, because once it is encapsulated into something else the engine will stop considering it “the default” and can cause crashes.
  • EditInstanceOnly you can think of this as the inverse of EditDefaultsOnly.

this is without mentioning the Blueprint specifiers which govern how these properties can be handled on the blueprint graph.

you can get more specifics by looking here All UPROPERTY Specifiers · ben🌱ui

some examples
UPROPERTY(EditAnywhere, BlueprintReadWrite)
the blueprint scripter, and Level Designer is given free reign over this property, and is being given full trust.

UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
the property is managed in C++ and shall not be modified through blueprints, or the details window, you can see what it is, but not modify it, it can also be referenced in blueprints, but only to use the current value (the blueprints can still call functions that can/will modify it)

if nothing is specified then the default behavior is EditAnywhere, and BlueprintReadWrite but by putting anything in the macro you remove these defaults (so assigning a category means you now need to specify the Edit/visibility and Blueprint privileges.

The two answers above doesn’t quiet fit the question. It was seemingly not possible to me, curious about the answer as well.

after reading through again sorry for initial confusion, the previous answers are about “exposing UPROPERTY to have it be viewable/Editable in details windows”

I am not sure what an appropriate title, but the concern as stated in the paragraph.

my past experience with Unity was 10 years ago (when they went to subscription instead of lifetime license), but from my memory technically everything that inherits from GameObject would be equivalent to an Unreal USceneComponent

the UPROPERTY governs how it can be shown in the Details window, and in the blueprint graph. while the class type and UCLASS() macros govern how it can be interacted.

to have it be added to a blueprint at all needs to have the UCLASS() specifiers of BlueprintType (this is true for structs as well to have those show up) and maybe meta=(BlueprintSpawnableComponent). for a UActorComponent and anything that inherits from them that are added through the Add C++ dialog window ‘should’ have these already.

for UActorComponent vs USceneComponent this comes down to the simple question of “does it need to have a transform?” or better put “does the component need to physically or logically need to exist in space?”
where a USceneComponent inherits from UActorComponent at the base class level the only difference is that USceneComponent has a transform, and is added to the hierarchy directly, while UActorComponent is just there with the AActor.

some example of USceneComponents:

  • UStaticMeshComponent and by inheritance USkeletalMeshComponent these are the most tangible example where everything from the Cube or plane you place for a floor or a wall to the body of your actor. anything that has physical form in your level is in most cases going to be one of these. or a UNiagaraSystem but that will still have a USceneComponent because…
  • AActor->RootComponent* every actor that is created will have a USceneComponent as the root component just so the Actor has a transform, this also enables us to do things like Attach actors to other Actors by virtue of thinking of an AActor as a USceneComponent

UActorComponents on the other hand are more abstract things like the

  • Movement Component it doesn’t need to have physical form, it just needs to know about the transform, but doesn’t need one itself.

some other don’t have too many direct examples in the engine, but some examples that could work:

  • character inventory: the inventory doesn’t need to exist in physical space, or have the inventory objects attached to it, it just needs to hold the data for those inventory items in some way.
  • character stats: I like to break these out of the ACharacter derived class so that I can give them to APawn or even make it so that a wall has health points if I need, and instead of casting to a class derived from AActor/APawn/ACharacter which can reduce modular design, and introduce memory overhead I can see if the Actor has a Component and just talk to that.

the selection of UActorComponent or USceneComponent only has implications on where in the hierarchy they appear (USceneComponents are in the hierarchical chain, while UActorComponents are listed bellow a horizontal bar after all the USceneComponents) and whether or not the object “needs a transform” because if everything has a transform that just adds to computational overhead to maintain the offsets.

for anything beyond this deep dive into the differences, or the previous about what to put in a UPROPERTY to make a member variable accessible/visible will need fallow up to the question.

You probably want VisibleAnywhere on the component property, and EditAnywhere on the float property.

It’s possible the component’s UCLASS also needs meta=(BlueprintSpawnableComponent), I’m not sure about that.

This should work

UCLASS()
class AMyClass : public AActor
{
    GENERATED_BODY()

public:
    AMyClass()
    {
        MyComponentReference = CreateDefaultSubobject<UMyComp>(TEXT("MyComponent"));
    }

    UPROPERTY(VisibleAnywhere)
    UMyComp* MyComponentReference;
};

UCLASS(Meta=(BlueprintSpawnableComponent))
class UMyComp : public UActorComponent
{
    GENERATED_BODY()

public:
    UPROPERTY(EditAnywhere)
    float MyVeryCoolFloat;
};