[UE5] FPS 재장전 기능 만들기

kkado·2024년 4월 25일
0

UE5

목록 보기
38/63
post-thumbnail

FPS에서 탄창 시스템과 재장전 기능은 빠질 수 없는 기능이다.
재장전 기능을 C++을 이용해서 만들어보자

Gun 클래스

탄창과 장전 기능은 라이플, 로켓 런처 등 다양한 총기류에서 공통적으로 갖고 있는 기능이 될 것이므로 Gun 클래스에 생성하는 것이 좋을 것이다.

(몰랐는데 탄창이 영어로 Magazine 이었다.)
탄창의 최대 총알 수를 MagCapacity로, 현재 탄창을 제외하고, 여분으로 갖고 있을 수 있는 최대 총알 수를 MaxAmmo 로 생성하였고, 이를 블루프린트에서 수정할 수 있게 프로파티를 지정했다.

CurrentMag 은 현재 탄창에 남아 있는 총알의 수, 그리고 CurrentAmmo는 현재 갖고 있는 여분 총알의 총합이다.

이외에 재장전에 필요한 시간 ReloadTime을 만들어서 재장전 키를 누르고 몇 초 뒤에 재장전이 완료될지를 지정할 수 있게 했다.

모두 private 섹션에 생성했으므로 이 클래스의 외부에서 변수 값을 가져오기 위한 Getter 함수도 생성했다.

void AGun::Reload()
{
	if (CurrentAmmo <= 0)
	{
		return;
	}
	int32 ToReload = FMath::Min(MagCapacity - CurrentMag, CurrentAmmo);
	CurrentMag += ToReload;
	CurrentAmmo -= ToReload;
}

Reload 함수는 위와 같이 구현했다.
예컨대 탄창이 30발이고 12/46이라고 하면 18발이 더 장전되어 재장전 후 30/28이 된다.
또는 12/10 이라고 하면 22/0이 된다. 따라서 '탄창에서 비어있는 양' 과 '여분 총알 수' 중에서 더 작은 값을 선택한다.

이 값만큼 CurrentMag에 더해주고 CurrentAmmo에서 차감해준다.
그리고 여분 총알이 아예 없다면 재장전할 수 없으므로 바로 return한다.


ShooterCharacter.h

이제 캐릭터 클래스에서 장전 기능을 추가로 구현해야 한다.

Input Action

먼저 Input Action을 생성한다. FPS의 국룰 재장전 키인 'R' 키로 생성한다.

Reload();

이제 InputAction에 바인딩할 함수를 만든다.

재장전 도중 발사 기능을 막기 위해, 그리고 재장전 중임을 나타내는 애니메이션 전환을 위해 현재 캐릭터가 재장전중인지를 나타내는 불리언 변수인 ReloadingState를 먼저 생성한다.

void AShooterCharacter::Reload()
{
	ReloadingState = true;
	FTimerHandle ReloadTimer;
	GetWorldTimerManager().SetTimer(ReloadTimer, this, &AShooterCharacter::CompleteReload, Gun->GetReloadTime());
}

그리고 Gun 클래스의 ReloadTime만큼 시간이 지난 후에 CompleteReload 함수를 호출하게끔 타이머를 설정한다.

void AShooterCharacter::CompleteReload()
{
	Gun->Reload();
	ReloadingState = false;
}

실질적 총알 정보를 업데이트하는 Gun->Reload() 함수를 호출하고, ReloadingState를 false로 만듦으로써 재장전을 마무리한다.


UI에 총알 정보 표시

체력 바를 나타내는 HUD에 총알 정보까지 추가해주자.

적절한 위치에 Horizontal Box를 만들고, 3개의 텍스트 상자를 이어 붙인다. 가운데 박스에는 슬래시(/)를 넣고, 앞에는 CurMag, 뒤에는 CurAmmo 정보를 바인딩할 것이다.

블루프린트에서 총알 정보를 가져올 수 있도록 ShooterCharacter.h에 Getter 함수를 BlueprintCallable UFUNCTION으로 생성한다.

UFUNCTION(BlueprintCallable)
int32 GetCurrentMag() const;

UFUNCTION(BlueprintCallable)
int32 GetCurrentAmmo() const;

바인딩 자체는 간단하다. PlayerController를 가져오고 -> 이를 ShooterCharacter로 캐스팅하고 -> 방금 만든 함수를 호출하여 리턴값을 아웃풋에 연결한다.

실행해보면 CurrentMagCurrentAmmo가 잘 바인딩되고 있다.

재장전도 잘 된다.


장전 애니메이션 만들기

먼저 에셋을 뒤져보며 장전과 관련된 애니메이션이 있는지 확인해 본다.

썩 맘에 들진 않지만... 일단 총을 내리고 뭔가 하는 것 같은 애니메이션이므로 이것을 사용하도록 하자.

위의 재장전 모션과 이동 모션을 IsReloading 이라는 불리언 변수에 따라 블렌드하도록 설정했다.

bool AShooterCharacter::IsReloading() const
{
	return ReloadingState;
}

IsReloading 변수는 ShooterCharacter에서 ReloadingState를 반환할 수 있도록 하는 BlueprintPure 함수이다.

이를 가져와서 블루프린트 상의 IsReloading 변수를 갱신한다.

일단 키를 누르면 애니메이션 전환이 잘 되긴 하는데, 하반신이 고정되어 있어서 움직임에 있어 매우 부자연스럽다.

이 부분은 다음 글에서 다룰 Bone (뼈) 단위 애니메이션 블렌드에서 다뤄보도록 하고 이번 글은 여기서 마무리...

profile
베이비 게임 개발자

0개의 댓글