Since picking up objects would be a common occurrence in the game im making, i wanted to make a PickupComponent. This would derive from ActorComponent, and it would have a CapsuleCollider to represent the pickup area. When the player enters this area, an event is fired and you can do whatever logic you want from there.
The problem comes from the fact that when i add this custom component to a simple blueprint actor (literally just a StaticMeshComponent), the capsule stays glued to world origin, or 0, 0, 0 in coordinates.
If you isolate the capsule and move it around as an individual object, nothing weird happens, but when you move the whole actor (the owning actor), the capsule snaps back to 0, 0, 0.
I’ve attached a video demonstrating this since it makes absolutely no sense to me
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "Components/CapsuleComponent.h"
#include "PickupComponent.generated.h"
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class UNREALIS_API UPickupComponent : public UActorComponent
{
GENERATED_BODY()
public:
// Sets default values for this component's properties
UPickupComponent();
protected:
// Called when the game starts
virtual void BeginPlay() override;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
class UCapsuleComponent* CapsulePickupRadius;
public:
// Called every frame
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
};
.cpp
#include "PickupComponent.h"
#include "Components/CapsuleComponent.h"
// Sets default values for this component's properties
UPickupComponent::UPickupComponent()
{
// Set this component to be initialized when the game starts, and to be ticked every frame. You can turn these features
// off to improve performance if you don't need them.
PrimaryComponentTick.bCanEverTick = true;
CapsulePickupRadius = CreateDefaultSubobject<UCapsuleComponent>(TEXT("CapsulePickupRadius"));
// ...
}
// Called when the game starts
void UPickupComponent::BeginPlay()
{
Super::BeginPlay();
// ...
}
// Called every frame
void UPickupComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
// ...
}
BeginPlay is too late to do this. You need to call this right after creating the default subobject.
At least, that’s what the documentation page says:
Initializes desired Attach Parent and SocketName to be attached to when the component is registered
But, like, just open up Lyra and see how they do it there:
ALyraWeaponSpawner::ALyraWeaponSpawner()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
RootComponent = CollisionVolume = CreateDefaultSubobject<UCapsuleComponent>(TEXT("CollisionVolume"));
CollisionVolume->InitCapsuleSize(80.f, 80.f);
CollisionVolume->OnComponentBeginOverlap.AddDynamic(this, &ALyraWeaponSpawner::OnOverlapBegin);
PadMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("PadMesh"));
PadMesh->SetupAttachment(RootComponent);
WeaponMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("WeaponMesh"));
WeaponMesh->SetupAttachment(RootComponent);
WeaponMeshRotationSpeed = 40.0f;
CoolDownTime = 30.0f;
CheckExistingOverlapDelay = 0.25f;
bIsWeaponAvailable = true;
bReplicates = true;
}
This should be all you need to do, assuming everything else is handled correctly. (Again – read through the Lyra code. It shows many things!)
Forgot to mark this post as a question, but this solved my issue. Since i have an ActorComponent and not an Actor i did the following:
.cpp
UPickupComponent::UPickupComponent()
{
// Set this component to be initialized when the game starts, and to be ticked every frame. You can turn these features
// off to improve performance if you don't need them.
PrimaryComponentTick.bCanEverTick = true;
SpherePickupZone = CreateDefaultSubobject<USphereComponent>(TEXT("SpherePickupZone"));
if(GetOwner())
SpherePickupZone->SetupAttachment(GetOwner()->GetRootComponent());
// ...
}