Download

Attaching Components before BeginPlay()?

This is a bit of a novice question. I have a component class which looks like this:



//The sensory component grants an object the ability to sense its surroundings via sight or hearing.
UCLASS(meta = (BlueprintSpawnableComponent))
class USensoryComponent : public UPrimitiveComponent
{
    GENERATED_BODY()

public:

    USensoryComponent(const FObjectInitializer& ObjectInitializer);
    virtual void InitializeComponent() override;
    virtual void BeginPlay() override;

    //This is the volume for which our sense is active.
    UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Senses")
    UShapeComponent* SensoryVolume;

};


I chose to use a UShapeComponent for the sensory volume because it can be changed to be either a sphere or a cone. What that shape is, is not known until it is assigned in a blueprint.



USensoryComponent::USensoryComponent(const FObjectInitializer& ObjectInitializer)
{
    if (SensoryVolume)//fails because this is always null within a constructor, even if assigned value by a blueprint
    {
        SensoryVolume->AttachToComponent(GetOwner()->GetRootComponent(), FAttachmentTransformRules(EAttachmentRule::KeepRelative, false));
    }
}

void USensoryComponent::BeginPlay()
{
    //This works, but not in the editor view.
    if (SensoryVolume)
    {
        SensoryVolume->AttachToComponent(GetOwner()->GetRootComponent(), FAttachmentTransformRules(EAttachmentRule::KeepRelative, false));
    }
}

void USensoryComponent::InitializeComponent()
{
    //This is never run. No idea why :(
    Super::InitializeComponent();

    if (SensoryVolume)
    {
        SensoryVolume->AttachToComponent(GetOwner()->GetRootComponent(), FAttachmentTransformRules(EAttachmentRule::KeepRelative, false));
    }
}


I want to be able to attach this shape (whatever it is) to the owning actor, so when the actor moves, so does the shape volume. I want to do this in C++, so that the user of my component doesn’t have to think about it and when they move the actor within the editor, the shape moves with it.

Normally, I would do this in the class constructor. However, I have realized that the lifecycle for the class doesn’t support this. If I assign a shape to my SensoryVolume class in blueprint, the class constructor doesn’t know about it (it is null). This leads me to believe that the class constructor is the very first method run when the class is created, and it is not fed values set by a blueprint. Somewhere in between BeginPlay() and the constructor, there must be a method for post construction. With actors, it is “PostInitializeComponents()”, but I can’t seem to find anything similar for UPrimitiveComponents. I tried to override the “InitializeComponent” method, but when I run my code, that method is never invoked.

I have tried putting my attachment into the BeginPlay() method, and this sort of works, but you don’t see the position of the shape volume in the editor, just within the game.

I have also tried putting the attachment logic into the blueprint constructor, and it works perfectly, but this is the wrong place to put it. Whoever uses my component would have to remember to do this attachment manually in every actor which uses the component, and that’s just asking for forgetfulness and human error.



.h
virtual void PostEditChangeProperty([FPropertyChangedEvent](https://docs.unrealengine.com/latest/INT/API/Runtime/CoreUObject/UObject/FPropertyChangedEvent/index.html) & PropertyChangedEvent) override;

.cpp
void MyClass::PostEditChangeProperty([FPropertyChangedEvent](https://docs.unrealengine.com/latest/INT/API/Runtime/CoreUObject/UObject/FPropertyChangedEvent/index.html) & PropertyChangedEvent){
Super::PostEditChangeProperty(PropertyChangedEvent);

if(UpdateCone){
UpdateCone = false;
//Run code to update the cone
}

}


^ Will run in editor when any property is changed. I’m not sure if it’ll run when objects are moved around though. If not, you can just make a bool called UpdateCone that runs your code when someone checks it on the property panel.

For actual actors, there’s another much better function that also works in editor called OnConstruction, though components don’t have that and must instead use PostEditChangeProperty.

Yeah… that’s kind of abusing the intended usage of that function. It’s an interesting idea though.

What I’m looking for is the Actor equivalent of “PostInitializedComponents” but for UPrimitiveComponents. I’m starting to think that it may not exist, or that I should make this entirely in C++ so that I can initialize a component within the class constructor and attach it to the owning actor. But even if I did that, I’d still run into the problem of not being able to read blueprint assigned values until after the constructor has finished running.

I think the method you want to override is OnRegister()