I wanted to implement a picking up hats functionality as shown in this video (Unreal Engine 4 - Attach Weapon to Hand - YouTube) using C++ (putting a hat pickup on the ground and if the player overlap with the hat, the hat will be destroyed and be attached to the player character’s “headSocket” socket).
I search the Unreal documentation and found these methods:
-
SetupAttachment(USceneComponent * InParent, FName InSocketName)
-
AttachToComponent(USceneComponent * InParent, const FAttachmentTransformRules & AttachmentRules, FName InSocketName)
They both need a reference to the skeletal mesh of the PlayerCharacter as the 1st parameter.
I tried passing the second line:
auto PlayerCharacter = UGameplayStatics::GetPlayerCharacter(GetWorld(), 0);
PlayerCharacter->GetMesh();
But it seemed not to work.
Other posts that I came across:
Can anyone tell me how to correctly use SetupAttachment()
and AttachToComponent()
or how to correctly reference the Skeletal mesh of PlayerCharacter?
Here are my codes:
HatPickup.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Components/StaticMeshComponent.h"
#include "Components/SphereComponent.h"
#include "Engine/SkeletalMesh.h"
#include "Components/SkeletalMeshComponent.h"
#include "HatPickup.generated.h"
UCLASS()
class WINTERCABIN_API AHatPickup : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AHatPickup();
//hat static mesh
UPROPERTY(VisibleAnywhere, Category = Mesh)
UStaticMeshComponent* HatMesh;
//overlap detection sphere
UPROPERTY(VisibleAnywhere, Category = Mesh)
USphereComponent* CollisionSphere;
UPROPERTY(VisibleAnywhere, Category = Mesh)
USkeletalMesh* PlayerMesh;
UPROPERTY(VisibleAnywhere, Category = Mesh)
USkeletalMeshComponent* PlayerMeshComponent;
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
UFUNCTION()
void Pickuped();
// declare overlap begin function
UFUNCTION()
void OnOverlapBegin(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
};
HatPickup.cpp
#include "HatPickup.h"
#include "Kismet/GameplayStatics.h"
#include "ConstructorHelpers.h"
// Sets default values
AHatPickup::AHatPickup()
{
// 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;
//Hat mesh
HatMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Hat"));
static ConstructorHelpers::FObjectFinder<UStaticMesh> HatMeshAsset(TEXT("/Game/_Mesh/Props/Clothing/Hat.Hat"));
if (HatMeshAsset.Succeeded())
{
HatMesh->SetStaticMesh(HatMeshAsset.Object);
}
RootComponent = HatMesh;
//Collision sphere
CollisionSphere = CreateDefaultSubobject<USphereComponent>(TEXT("CollisionShpere"));
CollisionSphere->SetupAttachment(RootComponent);
CollisionSphere->InitSphereRadius(50.0f);
}
// Called when the game starts or when spawned
void AHatPickup::BeginPlay()
{
Super::BeginPlay();
CollisionSphere->OnComponentBeginOverlap.AddDynamic(this, &AHatPickup::OnOverlapBegin);
}
// Called every frame
void AHatPickup::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void AHatPickup::Pickuped()
{
if (PlayerMeshComponent)
{
HatMesh->SetupAttachment(PlayerMeshComponent, TEXT("headSocket"));
Destroy();
}
}
void AHatPickup::OnOverlapBegin(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
if (OtherActor && (OtherActor != this) && OtherComp && OtherActor)
{
PlayerMeshComponent = Cast<USkeletalMeshComponent>(OtherActor);
Pickuped();
}
}