Editable Sub-Object Component Pointers

This is sort of a broad question concerning how sub-object pointers are meant to function in UE4. What I’ve been trying to do for a few days is to allow the editor to modify sub-object pointers to components of an actor.

For example:


UCLASS(config=Game)
class AMyActor: public APawn
{
    GENERATED_BODY()
public:
    UPROPERTY(EditAnywhere, Category = Character)
    UMyComponent* MySpecialComponent;
};

It should be clear what I want to do here. Anytime a user in the editor creates a component on this actor of type UMyComponent, I want them to be able to point the property MySpecialComponent at it so that AMyActor can use it for special things. If this were possible, it would strike me as an intensely useful tool for giving users the ability to customize the actors that they make.

I would like this to work for both Blueprint archetypes as well as instances, but would be okay if it only applied to archetypes. As it stands, the property will only show up in the details panel at all if it’s an instance, and there is no way to edit those pointers. My foray into making some editor code to manually point them resulted in a variety of issues I believe related to this bug.

The whole thing has left me confused what the engine’s intent is for sub-objects and default sub-objects. CreateDefaultSubobject lets the class create, well, a default sub-object but the user can’t replace it with anything else?

The question extends to widgets and UMG. If I have a class that inherits UUserWidget I want the user to be able to specify pointers to sub-widgets. For example, if the user wants an image to receive, in code, something game-related, it would make a lot of sense for the user to be able to point a property in that UUserWidget to that sub-widget. Unity is very seamless with stuff like this, allowing you to specify internal object references with no problem, allowing for a huge amount of editor customization, but I’m sitting here sort of lost in Unreal.

I just stumbled upon this issue as well. Did you eventually find any solution to it?

Ok, it seems that this kind-of works for archetypes in 4.9: assigning a component pointer in an archetype adds a new default subcomponent to that actor. However, it seems to be still impossible to a) make a pointer in an archetype to point to an existing default subcomponent, and to b) make a pointer in an instance to point to an existing subcomponent instance. I will open a new question for this.

Edit How to make component pointers assignable in the editor? - Programming & Scripting - Unreal Engine Forums

Hey -

I’m not sure I understand what your goal is. Can you elaborate on what you’re trying to accomplish? When a pointer to a component is created in code the pointer has to be instantiated with the component to be created. Using the above code as an example, this is done by adding MySpecialComponent = CreateDefaultSubobject(TEXT("MySpecialComponent")); inside the class constructor. This is what will create the component as part of the actor and allow the properties of the component to be edited both inside the editor as well as in code. Below is another example of editing the component in code where I’ve created a sphere component and then set the radius of the sphere. This default value can then be overriden inside a blueprint if necessary.

    UPROPERTY(EditAnywhere, Category = Component)
        USphereComponent* MySphereComp;

MySphereComp = CreateDefaultSubobject<USphereComponent>(TEXT("MySphereComp")); 
MySphereComp->SetSphereRadius(453.0f);

Hi ,

Maybe it is best if I show a complete use case, so as to also give some context to this.

Repro

Create a new Basic Code project (no starter content needed).

Create a new Blueprint class that inherits from Actor. Let’s call it MyActor.

Create a new C++ class that inherits from Actor Component. Let’s call it Spinner.

Save and close the editor.

Add the following to the public section of Spinner.h:

UPROPERTY( EditAnywhere, BlueprintReadWrite )
UActorComponent * SpinTarget = 0;

Add the following to USpinner::TickComponent() in Spinner.cpp:

if( UPrimitiveComponent * primitiveTarget = dynamic_cast<UPrimitiveComponent *>(SpinTarget) )
{
	primitiveTarget->AddTorque( FVector( 0.f, 0.f, 1e6f ) );
}

Compile and relaunch the editor.

Open MyActor in the Blueprint editor.

Add two cube components; let’s call them Cube1 and Cube2. Move them a bit apart in the viewport. Enable Simulate Physics for both.

Add a Spinner component.

Go back to the level editor and drop a MyActor instance to the scene. Position it slightly above the floor.

In World Settings, tick Override World Gravity (so as to disable gravity).

You should now have something like this:

Now, in this case, the user of the Spinner component could easily select the target component to be spun using the construction script of MyActor:

62904-repro3.png

62905-repro4.png

However, this can become messy or plain impossible in more complex scenarios. At the same time, I do not see how to achieve the same by assigning the SpinTarget variable directly in the editor. The SpinTarget fields can be seen in the first two screenshots (marked with red). For the MyActor instance (first screenshot from the level editor), the drop-down list shows all Actor Component classes, instead of the Actor Component instances present in the current actor. Nothing happens if I select one. For the MyActor archetype (second screenshot from the Blueprint editor), the drop-down list shows also all ActorComponent classes. If I select one, a new component becomes created in the instance, instead of letting me to select one of the already existing cubes:

62906-repro5.png

What is visible in the last screenshot is probably the intended behavior for creating new default subobjects.

However, my (our?) goal is to select and make the pointer to point at an existing component, ie, Cube1 or Cube2 in this case, which I do not know how to do.

So, in essence, somehow replacing this drop-down list (don’t mind the differing variable names):

62794-capture2.png

with an actor-picker-style selector box that would let me select between Cube1 and Cube2:

62793-capture1.png

Would solve the problem.

I am wondering whether there is a way to do this, or whether there is another approach to accomplish this, or is the current behavior a bug in the engine?

The ability to create a pointer in code and set that pointer to specific blueprint component added in the editor does not exist, however I have entered a feature request (UE-22265) for this functionality.

In case it helps it is possible to have a pointer store a component during runtime. Rather than using UActorComponent you can use USceneComponent to create the pointer. Then if you get all of the components of an actor you can loop through the array for a specific component or choose which element number to store into the pointer.

Has this been completed since then? I am trying to let my designers assign a specific camera component in the editor rather than hardcoding which camera is being used.

I’m writing a new thread now - Select component type in editor - Programming & Scripting - Unreal Engine Forums

I am also trying to do the exact same thing here; in my case, I’m trying to create a component that can be added to an actor and which allows the user to select an instance of a UMeshComponent that already exists in the parent actor.

Unreal 4.13.2 user here. I don’t think this is exactly what you needed, but I figured out a way to have a pointer that points to an instantiated actor component. Here’s my situation:

I wanted a ComponentActivator component that would activate a specific component when being overlapped. What I did is that I added a TSubclassOf ClassOfComponentToActivate variable (editable anywhere) and a UActorComponent *ComponentToActivate variable. Basically, after having added the ComponentActivator to the actor, the user specify a class to ClassOfComponentToActivate and then in the PostEditChangeProperty function I retrieve the component by using GetComponentByClass and store the result in ComponentToActivate. Obvisouly you have to make sure that a component of the specified class is present on the actor, but it’s not too big of a problem I think. Here’s the code:

////// ComponentActivator.h //////

UCLASS(ClassGroup = (Activation), meta = (BlueprintSpawnableComponent))
class ROBOT_API UComponentActivator : public UBoxComponent
{
	GENERATED_BODY()

protected:
	// Allows the user to specify the class of the component to be activated
	UPROPERTY(EditAnywhere)
	TSubclassOf<UActorComponent> ClassOfComponentToActivate;

private:
	// Pointer to the actual component to be activated
	// Will be set in the PostEditChangeProperty function
	UPROPERTY()
	UActorComponent *ComponentToActivate = nullptr;

public:
	UComponentActivator();

	// Called whenever a property on the component is changed
	virtual void PostEditChangeProperty(FPropertyChangedEvent &PropertyChangedEvent) override;
	
	UFUNCTION()
	void OnComponentBeginOverlapEvent(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult &SweepResult);
	
};



//////	ComponentActivator.cpp //////

UComponentActivator::UComponentActivator()
{
	bGenerateOverlapEvents = true;
	OnComponentBeginOverlap.AddDynamic(this, &UComponentActivator::OnComponentBeginOverlapEvent);
}

void UComponentActivator::PostEditChangeProperty(FPropertyChangedEvent &PropertyChangedEvent)
{
	Super::PostEditChangeProperty(PropertyChangedEvent);

	if (!ClassOfComponentToActivate)
	{
		ComponentToActivate = nullptr;
	}
	else
	{
		ComponentToActivate = GetOwner()->GetComponentByClass(ClassOfComponentToActivate);
	}
}

void UComponentActivator::OnComponentBeginOverlapEvent(UPrimitiveComponent * OverlappedComponent, AActor * OtherActor, UPrimitiveComponent * OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult & SweepResult)
{
	if (!ComponentToActivate)
	{
		return;
	}

	ComponentToActivate->SetActive(true);
	ComponentToActivate->SetComponentTickEnabled(true);
}

Apparently CreateDefaultSubobject has multiple overload. I just tried and this seems to compile fine.

	TSubclassOf<UPCGameplayUnitComponent> TestClass;
	UPCGameplayUnitComponent* TestComp;
	TestComp = Cast<UPCGameplayUnitComponent>(PCIP.CreateDefaultSubobject(GetOuter(),TEXT("GameplayUnitComponent2"), TestClass, TestClass, false, true, true));

So, there is no way? what i am doing rn is setting the component tag, finding components with tag and selecting the component in code, which is ok, but i have to use tags, anybody found a better way?

Hey Guys,
I think i found a good solution.

Header

UPROPERTY(EditDefaultsOnly, Category = "Camera|FirstPerson")
FName FirstPersonCameraParentName = "Mesh";

USceneComponent* FPAttachParent;

CPP

void ATP_ThirdPersonCharacter::BeginPlay()
{
	Super::BeginPlay();

	FPAttachParent = Cast<USceneComponent>(GetDefaultSubobjectByName(FirstPersonCameraParentName));
}

Now just specify the name you gave the component and you’re good to go.
It also does not matter if the component was added in blueprint or in c++.

If you want to find by name you can use this:

class UNavigationComponent* Component;

UPROPERTY(EditAnywhere)
FComponentReference ComponentReference;

The component reference is basicly that, but it finds the component and you can even make a component picker if you are planing on using this to edit only instances

1 Like

Neat. Thank you!