블루프린트 없이 c++로 무기 획득 상자 제작하기

유영준·2023년 1월 14일
0
post-thumbnail

저번 내용과 이어서 이번에는 캐릭터가 시작하자마자 무기를 습득하는 것이 아닌, 상자를 획득했을때 무기를 장착하도록 구현해보겠다

오브젝트 채널 추가하기

먼저 오브젝트 채널을 추가해준다

이름은 ItemBox, Default ResponseIgnore 로 해둔다

이후 ItembBox 프리셋을 만들고 유형을 만들어둔 ItemBox 채널로 한 후 상호작용할 캐릭터를 제외 모두 Ignore 시켜둔다

이때, 캐릭터 프리셋에서도 기본적으로는 ItemBox가 Ignore로 지정되어있기 때문에, Overlap 으로 바꿔주자

이제, 이 둘은 서로 Overlap 이 가능하고, 추후 둘이 충돌하였을때, OnComponentOverlap 함수를 통해 무기를 장착하도록 구현할 것이다


상자 액터 생성

액터를 부모로 하는 상자 클래스를 생성해준다

헤더에는 Trigger 포인터 변수, 스태틱 메시 변수, 파티클 시스템, 아이템 클래스 변수, 이렇게 4가지의 변수와

PostInitializeComponents, 충돌 시를 설정해줄 OnCharacterOverlap, 파티클이 끝난 후 실행되는 함수 OnEffectFinished 를 만들어준다

ABItem.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "ArenaBattle.h"
#include "GameFramework/Actor.h"
#include "ABItem.generated.h"

UCLASS()
class ARENABATTLE_API AABItem : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	AABItem();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;
	virtual void PostInitializeComponents() override;

public:	
	UPROPERTY(VisibleAnywhere, Category = Box)
	UBoxComponent* Trigger;

	UPROPERTY(VisibleAnywhere, Category = Box)
	UStaticMeshComponent* Box;

	UPROPERTY(VisibleAnywhere, Category = Effect)
	UParticleSystemComponent* Effect;

	UPROPERTY(EditInstanceOnly, Category = Box)
	TSubclassOf<class AABWeapon> WeaponItemClass;

private:
	UFUNCTION()
	void OnCharacterOverlap(UPrimitiveComponent* OVerlappedComp, AActor* OtherActor, 
		UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);

	UFUNCTION()
	void OnEffectFinished(class UParticleSystemComponent* PSystem);
};

TSubclassof 를 사용하면 특정 클래스만 보이게 된다 이를 통해 불필요하게 많은 정보가 뜨는 것을 방지할 수 있다
OnCharacterOverlapOnEffectFinished 는 언리얼에서 제공하는 다이나믹 델리게이트 함수들이다
그렇기 때문에 UFUNCTION 을 붙여줘야 한다

상자 스태틱 메시와 이펙트는 각각 Box 를 검색 후 찾을 수 있는 SM_Env_Breakables_Box1

Chest 를 검색 후 찾을 수 있는 P_TreasureChest_Open_Mesh 이다

둘을 레퍼런스 주소로 삼아 cpp 파일을 작성하자

단 이때, OnCharacterOverlap 함수는 ABCharacter.cpp 파일에 수정이 필요하기 때문에, 아직 작성하지 않는다

ABItem.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "ABItem.h"
#include "ABCharacter.h"
#include "ABWeapon.h"

// Sets default values
AABItem::AABItem()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = false;

	
	Trigger = CreateDefaultSubobject<UBoxComponent>(TEXT("TRIGGER"));
	Box     = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("BOX"));
	Effect  = CreateDefaultSubobject<UParticleSystemComponent>(TEXT("Effect"));
	
    // 트리거를 루트 컴포넌트로 지정
	RootComponent = Trigger;
	Box   ->SetupAttachment(RootComponent);
	Effect->SetupAttachment(RootComponent);

	//트리거의 사이즈와 크기를 지정
	Trigger->SetBoxExtent(FVector(26.5f, 27.5f, 13.5f));
	Trigger->SetRelativeScale3D(FVector(1.5f, 1.5f, 1.5f));

	static ConstructorHelpers::FObjectFinder<UStaticMesh> SM_BOX
	(TEXT("/Game/InfinityBladeGrassLands/Environments/Breakables/StaticMesh/Box/SM_Env_Breakables_Box1.SM_Env_Breakables_Box1"));
	if (SM_BOX.Succeeded())
		Box->SetStaticMesh(SM_BOX.Object);

	static ConstructorHelpers::FObjectFinder < UParticleSystem> P_CHESTOPEN
	(TEXT("/Game/InfinityBladeGrassLands/Effects/FX_Treasure/Chest/P_TreasureChest_Open_Mesh.P_TreasureChest_Open_Mesh"));
	if (P_CHESTOPEN.Succeeded())
	{
		Effect->SetTemplate(P_CHESTOPEN.Object);
		Effect->bAutoActivate = false;
	}

	// 박스와 이펙트의 위치를 조정해줘 자연스럽게 보이도록 구성
	Box->SetRelativeLocation(FVector(0.0f, -3.5f, -13.5f));
	Effect->SetRelativeLocation(FVector(0.0f, 0.0f, -45.0f));

	Trigger->SetCollisionProfileName(TEXT("ItemBox"));
	Box    ->SetCollisionProfileName(TEXT("NoCollision"));

	WeaponItemClass = AABWeapon::StaticClass();
}

// Called when the game starts or when spawned
void AABItem::BeginPlay()
{
	Super::BeginPlay();
	
}

void AABItem::PostInitializeComponents()
{
	Super::PostInitializeComponents();
    // AddDynamic 매크로를 통해 OnCharacterOverlap 함수를 OnComponentBeginOverlap 델리게이트에 추가
	Trigger->OnComponentBeginOverlap.AddDynamic(this, &AABItem::OnCharacterOverlap);
}

void AABItem::OnEffectFinished(UParticleSystemComponent* PSystem)
{
	Destroy();
}


캐릭터가 아이템을 습득가능하도록 변경하기

ABCharacter.h 에 무기 장착이 가능한지 파악하는 bool 변수, 장착시키는 함수, 현재 장착하고 있는 무기 변수를 만들어준다

ABCharacter.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "ArenaBattle.h"
#include "GameFramework/Character.h"
#include "ABCharacter.generated.h"

UCLASS()
class ARENABATTLE_API AABCharacter : public ACharacter
{

	...

public:

	...
    
	bool CanSetWeapon();
	void SetWeapon(class AABWeapon* NewWeapon);

	UPROPERTY(VisibleAnywhere, Category = Weapon)
	class AABWeapon* CurrentWeapon;

	...

};

이후 저번에 작성한 BeginPlay 에 있는 무기 액터를 장착시키는 스크립트는 지워준다

ABCharacter.cpp

...

bool AABCharacter::CanSetWeapon()
{
	return (nullptr == CurrentWeapon);
}

void AABCharacter::SetWeapon(AABWeapon* NewWeapon)
{

	FName WeaponSocket(TEXT("hand_rSocket"));
	if (nullptr != NewWeapon)
	{
		NewWeapon->AttachToComponent(GetMesh(), FAttachmentTransformRules::SnapToTargetNotIncludingScale, WeaponSocket);
		NewWeapon->SetOwner(this);
		CurrentWeapon = NewWeapon;
	}
}

...

이제 다시 ABItem.cpp 에 돌아가 OnCharacterOverlap 함수를 완성해주자

ABItem.cpp

...

void AABItem::OnCharacterOverlap(UPrimitiveComponent* OVerlappedComp, AActor* OtherActor, 
	UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
	auto ABCharacter = Cast<AABCharacter>(OtherActor);
	if (nullptr != ABCharacter && nullptr != WeaponItemClass)
	{
		if (ABCharacter->CanSetWeapon())
		{
			auto NewWeapon = GetWorld()->SpawnActor<AABWeapon>(WeaponItemClass, FVector::ZeroVector, FRotator::ZeroRotator);
			ABCharacter->SetWeapon(NewWeapon);
			Effect->Activate(true);
			Box->SetHiddenInGame(true, true);
			SetActorEnableCollision(false);
			Effect->OnSystemFinished.AddDynamic(this, &AABItem::OnEffectFinished);
		}
	}
}

...

마지막으로 컴파일 후 캐릭터가 상자와 접촉할때 무기를 습득하며 이펙트가 잘 나오는지 확인하자

profile
토비폭스가 되고픈 게임 개발자

0개의 댓글