본문 바로가기
언리얼엔진 개발/Developing

[UnrealEngine5] 플레이어가 총알을 발사하게 하는 법

by yeni_0224 2023. 7. 13.
728x90
반응형

플레이어가 총알을 발사하려면

총을 들고있는 자세의 애니메이션이 필요할 것이고, 총이 필요할 것이고, 총알도 필요할 것이다.

1. 총알부터 만들어보자

소스코드 클래스가 들어있을 폴더에 들어가 우클릭하여 추가해줄 것이고, Actor로 만들 것이다.

	UPROPERTY(EditDefaultsOnly, Category="Bullet Settings")
	class USphereComponent* sphereComp;
	UPROPERTY(EditDefaultsOnly, Category="Bullet Settings")
	class UStaticMeshComponent* meshComp;

헤더에 Collision용과 Mesh 변수를 선언해주고

#include "Bullet.h"
#include "Components/SphereComponent.h"
#include "Components/StaticMeshComponent.h"

ABullet::ABullet()
{
	PrimaryActorTick.bCanEverTick = true;

	sphereComp = CreateDefaultSubobject<USphereComponent>(TEXT("sphereComp"));
	SetRootComponent(sphereComp);
	meshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("meshComp"));
	meshComp->SetupAttachment(RootComponent);
    meshComp->SetRelativeScale3D(FVector(0.3f));
}

생성자에 추가해준다. Sphere의 사이즈도 미리 설정해주었다.

엔진의 C++ 클래스에 있는 것 우클릭 해서 BP로 만들어주고나면 Bullet에 대한 BP 클래스가 만들어지고 sphere과 mesh가 생긴 것을 확인할 수 있다. 근데 AnimationBP를 만들 때에는 그냥 AnimationBP를 만들고 Reparent시켜줘야 소스코드 클래스를 상속받는 AnimationBP가 생성되었다. 

Mesh도 잘 맞게 설정해주었다. 그 다음 이제 무엇을 할것이냐. 총알이 나오는 곳을 설정할 것이다.

2. 총알이 나오는 곳

총은 총알이 나오기 위한 위치를 잡아주는 껍데기에 불과하다.

총의 위치는 나중에 잡아주도록 하고, 지정된 위치에서 총알이 앞으로 나오도록 할 것이다.

플레이어의 위치에서 1미터 떨어진 곳에서 총알을 발사하도록 할 것이다. 되도록이면 소스코드로 구현하도록 할 것이다. 프로젝트를 하면서 느꼈지만 블루프린트 정말 여리고 연약해서 잘 깨진다. 그럼에도 불구하고 블루프린트로 간단하게 구현해보자.

Player BP에서 SPawn Actor from Class를 선택한 후 BP_Bullet을 할당해준다. 그 다음 총알이 spawn 될 위치를 지정해주기 위해서 오른쪽 세개의 노드를 준비했고, Transform 부분을 우클릭하여 Split 해준 후 rotation과 location을 연결해준다

float 값을 곱해주어 거리를 설정해주기 위해 * 노드를추가하고, x y z 부분을 우클릭해 float형으로 바꿔주었다.

이걸 이제 Fire하는 키와 연결해줘야한다.

3. Fire 키 바인딩 하기

역시나 Input 만들어주고, IMC에서 Fire 버튼을 만들어준다.

소스코드로 넘어와서 Fire 함수와, 변수를 만들어주고 키를 바인딩 해준다.

/*Player.h*/
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category= Input, meta = (AllowPrivateAccess = "true"))
class UInputAction* IA_Fire;

void Fire();

/*Player.cpp*/
//Fire
EnhancedInputComponent->BindAction(IA_Fire, ETriggerEvent::Started, this, &ANewProjCharacter::Fire);

총알이 발사 되도록 총알을 담아두는 공간을 만들어야 하고, 발사하는 기능을 만들어볼 것이다. 플레이어의 헤더파일에 이 변수를 추가해줄 것이다.

UPROPERTY(EditDefaultsOnly, Category = "Bullet Settings")
TSubclassOf<class ABullet> bulletFactory;

그 다음 총알이 플레이어의 위치로부터 1미터 떨어진 곳에서 발사되도록 해줄 것이다.

void ANewProjCharacter::Fire()
{
	auto fireLoc = GetActorLocation() + GetActorForwardVector() * 1;
	GetWorld()->SpawnActor<ABullet>(bulletFactory, fireLoc, GetActorRotation());
}

그 다음 엔진으로 넘어와서 플레이어  BP에서 Input과 bullet Factory를 할당해줄 것이다.

BP_Player

클릭하면 이렇게 총알이 발사되는데 딱 이 위치에만 떠있고, 앞으로 나아가는 느낌이 없다. 자연스럽게 앞으로나아갈 수 있도록 해줄 것이다. 또한 발사될 때 공에 밀려 카메라와 플레이어가 움직일 수 없게 막히기 때문에 이 충돌문제도 해결해줄 것이다.

반응형

 

(1) 총알과 플레이어의 충돌 문제 해결하기

일단 Mesh와 Collision Sphere의 충돌 설정을 해줄 것이다.

Project Setting > Collision에 들어와 Bullet과 Player 충돌 프리셋을 만들어줄 것이다. 이 체크 내용은 계속 조금씩 수정해나가면서 본인이 원하는 세팅을 맞춰주면 되는 것이다.

여기에 작성한 이름 그대로 소스코드에 profilename을 넣어주어야한다.

//Bullet의 생성자 안에서
sphereComp->SetCollisionProfileName(TEXT("BulletPreset"));
meshComp->SetCollisionEnabled(ECollisionEnabled::NoCollision);

 플레이어의 Collision Preset은 Player로 설정을 변경해주면 된다.

 

(2) 총알 나가기

그 다음 두 오브젝트 중 실질적으로 움직이고 있는 오브젝트가 무엇인지 명확하게 지정해주어도 좋다.

	//Bullet 헤더
    UPROPERTY(EditAnywhere, Category= "Bullet Settings")
	class UProjectileMovementComponent* moveComp;

이런 변수를 하나 만들어보고 생성자에 이렇게 추가해보는 것이다.

	moveComp = CreateDefaultSubobject<UProjectileMovementComponent>(TEXT("moveComp"));
	moveComp->SetUpdatedComponent(sphereComp);
	moveComp->InitialSpeed = 5000;
	moveComp->MaxSpeed = 5000;
	moveComp->bShouldBounce = true;
	moveComp->Bounciness = 0.3f; //이런 것도 설정할 수 있다. 총알이 튕기는 정도 인듯?

bShouldBounce가 false일 경우 총알이 발생하지 않는다.

총알이 발생할 위치를 지정해줄 것이다. 블루프린트에서 만들었던 노드 그대로 써줄 것이다.

void ANewProjCharacter::Fire()
{
	auto fireLoc = GetActorLocation() + GetActorForwardVector() * 1;
	GetWorld()->SpawnActor<ABullet>(bulletFactory, fireLoc, GetActorRotation());
	UE_LOG(LogTemp, Warning, TEXT("Fire Bullet"))
}

한 번 발사할 때 총알 1개씩 나가고, 반동도 생겼다!

 

(3) 발사된 총알 사라지게 (메모리 관리를 위함)

발사된 총알은 맵의 인스턴스 상에 남는다. 계속 놔두게 된다면 효율적이지 못하기 때문에 발사된 총알은 사라지게 할 것이다.

void ABullet::BeginPlay()
{
	Super::BeginPlay();
    
	FTimerHandle bulletTimer;
	GetWorld()->GetTimerManager().SetTimer(bulletTimer, this, &ABullet::DestroyMySelf, 2.f);
}

총알이 발사되면 2초 뒤에 삭제 되도록 TimerHandle을 사용할 것이다. DestroyMySelf 함수와 연결해주었다. 그 함수 안에는 인스턴스를 없애는 함수가 들어있다.

void ABullet::DestroyMySelf()
{
	Destroy();
}

총알을 발사하는 다른 방법도 소개하면 좋을 것 같다!

728x90
반응형