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.