게임 개발 (언리얼 엔진)

UE4 생존게임 제작 - 15 (UI 제작 및 다양한 사운드 처리)

언린이 2020. 11. 17. 01:41

1. 화살 개수 UI 제작

 

 

 

먼저 UMG를 생성한 후,

 

 

 

화살 아이콘과 현재 화살의 개수와 가지고 있을 수 있는 화살의 최대수를 나타내는 TextBlock으로 위젯 블루프린트 클래스를 꾸몄습니다.

 

 

public:
	UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (AllowPrivateAccess = "true"))
	class UTextBlock* ArrowNum;

	UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (AllowPrivateAccess = "true"))
	class UTextBlock* ArrowNumMax;

 

void UUIArrowState::NativeConstruct()
{
	Super::NativeConstruct();

	ArrowNum = Cast<UTextBlock>(GetWidgetFromName(TEXT("ArrowNum")));
	ArrowNumMax = Cast<UTextBlock>(GetWidgetFromName(TEXT("ArrowNumMax")));
}

 

C++ 클래스에서 TextBlock을 나타내는 변수를 선언한 뒤, GetWidgetFromName 함수를 통해 두 TextBlock을 위젯 블루프린트 클래스에서 불러왔습니다.

 

 

// 현재 화살 개수를 세팅하는 함수
void UUIArrowState::SetArrowNum(int32 ArrowCount)
{
	FString strText;
	strText = FString::Printf(TEXT("%d"), ArrowCount);

	ArrowNum->SetText(FText::FromString(strText));
}

// 최대 화살 개수를 세팅하는 함수
void UUIArrowState::SetArrowNumMax(int32 ArrowCountMax)
{
	FString strText;
	strText = FString::Printf(TEXT("%d"), ArrowCountMax);

	ArrowNumMax->SetText(FText::FromString(strText));
}

 

그리고 나서 두 가지 TextBlock에 Text를 세팅하는 함수를 정의해주었습니다.

 

 

2. Main 위젯에 화살 개수 UI 추가

 

 

화살 개수 UI를 Main 위젯에 추가해준 후,

 

 

	UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (AllowPrivateAccess = "true"))
	UUIArrowState* ArrowState;

 

	ArrowState = Cast<UUIArrowState>(GetWidgetFromName(TEXT("UI_ArrowState")));

 

변수를 선언한 뒤, GetWidgetFromName 함수를 통해 위젯 블루프린트 클래스에서 화살 개수 UI를 불러왔습니다.

 

 

	UUIArrowState* GetArrowState() const
	{
		return ArrowState;
	}

 

그리고 나서 화살의 개수나 최대 화살 개수가 변할 때마다 Text를 새로 세팅해주기 위해 화살 개수 UI를 return 해주는 함수를 만들었습니다.

 

 

	ArrowState = SurvivorStateWidget->GetArrowState();

 

그 다음 플레이어 클래스의 BeginPlay 함수에서 화살 개수 UI를 받아와서 가지고 있도록 해주었습니다.

이제 화살 개수나 화살 최대 개수가 변할 때마다 Text를 새로 세팅해주면 됩니다.

 

 

// 화살 사용시 화살 개수를 감소시키는 함수
void APlayerSurvivor::ReduceArrowNum()
{
	UInventoryItemData* Arrow = Cast<UInventoryItemData>(List->GetItemAt(7));

	// 화살 개수 감소
	Arrow->SetItemCount(Arrow->GetItemCount() - 1); 

	// Arrow State 업데이트
	if (IsValid(ArrowState))
		ArrowState->SetArrowNum(Arrow->GetItemCount());

	// List 업데이트
	List->RegenerateAllEntries();
}

 

플레이어가 화살을 사용할 시 화살 개수를 감소시키는 함수를 호출하여 화살 개수 UI와 인벤토리를 업데이트 해주었습니다.

 

 

 

이제 화살을 사용하면 화살 개수 UI의 상태가 업데이트되는 모습을 확인할 수 있습니다.

 

 

3. 플레이어 발자국 사운드 처리

 

 

발자국 사운드를 처리하기 위해서 플레이어가 어떤 재질을 밟고 있는지 알 필요가 있습니다.

그래서 각 재질마다 피지컬 매터리얼을 만들어주었습니다.

 

 

 

그런 다음 각 레이어마다 피지컬 매터리얼을 입혀주었습니다.

 

 

 

발자국 소리가 플레이어의 발이 땅에 닿을 때마다 나야하기 때문에 애니메이션에서 발이 땅에 닿는 부분에 노티파이를 만들어주었습니다. 이제 해당 노티파이에서 발자국 사운드를 재생하면 됩니다.

 

 

 

노티파이를 불러온 후, 플레이어의 발에 있는 소켓의 위치를 불러왔습니다.

 

 

 

플레이어의 소켓 위치를 LineTraceByChannel에 넣어준 후, 피지컬 매터리얼의 이름을 이용하여 Switch 문을 실행하였습니다.

 

 

 

마지막으로 각각의 피지컬 매터리얼마다 알맞은 사운드를 PlaySoundAtLocation 함수를 사용하여 재생해주었습니다.

 

 

4. 배경음악 재생

 

 

먼저 배경음악으로 재생할 사운드 큐를 생성하였습니다.

 

 

 

그리고 나서 배경음악으로 재생될 웨이브 파일들을 가져온 후, Concatenator에 연결해주었습니다.

Concatenator는 웨이브 파일들을 순차적으로 재생시켜주는 노드입니다.

그 다음 배경음악은 무한 재생이 되어야 하기 때문에 Looping 노드에 연결해주고 출력하였습니다.

 

 

protected:
	class UAudioComponent* AudioComponent;
	class USoundCue* MainMusicCue;

 

그 다음 MainGameMode 클래스에서 AudioComponent와 SoundCue 변수를 선언해주었습니다.

 

 

	static ConstructorHelpers::FObjectFinder<USoundCue> MainMusicAsset(TEXT("SoundCue'/Game/FantasyOrchestral/cues/MainGameSound.MainGameSound'"));

	if (MainMusicAsset.Succeeded())
		MainMusicCue = MainMusicAsset.Object;

	AudioComponent = CreateDefaultSubobject<UAudioComponent>(TEXT("AudioComponent"));
	AudioComponent->bAutoActivate = false;

 

생성자에서 SoundCue 애셋을 불러와서 저장해주고 AudioComponent를 초기화해주었습니다.

 

 

void AMainGameMode::BeginPlay()
{
	Super::BeginPlay();

	// 배경음악 재생
	AudioComponent->SetSound(MainMusicCue);
	AudioComponent->Play();
}

 

BeginPlay 함수에서 AudioComponent에 저장해둔 SoundCue 애셋을 세팅하고 재생해주었습니다.

 

 

5. 각종 사운드 이펙트 처리

 

 

여러가지 사운드 이펙트들은 웨이브 파일을 재생하여 처리해주었습니다.

 

 

protected:
	// 화살 나가는 소리
	class USoundWave* ArrowProjectileSound;
	
	// 제작 아이템 만드는 소리
	class USoundWave* MakingSound;
	
	// 제작 실패 소리
	class USoundWave* UnMakingSound;

 

먼저 SoundWave 변수들을 선언하였습니다.

 

 

	static ConstructorHelpers::FObjectFinder<USoundWave> ArrowProjectileAsset(TEXT("SoundWave'/Game/Audio_Asset/Weapons/PistolShot01.PistolShot01'"));

	if (ArrowProjectileAsset.Succeeded())
		ArrowProjectileSound = ArrowProjectileAsset.Object;

	static ConstructorHelpers::FObjectFinder<USoundWave> MakingSoundAsset(TEXT("SoundWave'/Game/Audio_Asset/Environment/PickUp.PickUp'"));

	if (MakingSoundAsset.Succeeded())
		MakingSound = MakingSoundAsset.Object;

	static ConstructorHelpers::FObjectFinder<USoundWave> UnMakingSoundAsset(TEXT("SoundWave'/Game/Audio_Asset/Elecronic/WrongCode.WrongCode'"));

	if (UnMakingSoundAsset.Succeeded())
		UnMakingSound = UnMakingSoundAsset.Object;

 

그 다음 생성자에서 SoundWave 애셋들을 불러와서 저장해주었습니다.

 

 

	// 전체 소리로 사운드 재생하는 함수
	if (bMakeItem)
		UGameplayStatics::PlaySound2D(this, MakingSound, 2.5f);
	else
		UGameplayStatics::PlaySound2D(this, UnMakingSound, 0.5f);

 

	// 특정 지점에서 사운드 재생하는 함수
	UGameplayStatics::PlaySoundAtLocation(this, ArrowProjectileSound, vPos, 0.5f);

 

마지막으로 사운드를 재생하고 싶은 곳에서 PlaySound2D 함수나 PlaySoundAtLocation 함수를 사용하여 재생해주면 됩니다.

PlaySound2D 함수는 전체 소리로 사운드가 재생되고 PlaySoundAtLocation 함수는 특정 지점에서 사운드가 재생됩니다.

화살이 발사되는 사운드같은 경우는 화살이 발사되는 지점, 즉 활 앞부분에서 재생되면 더 현실감이 있기 때문에 PlaySoundAtLocation 함수를 사용하여 처리하였습니다.

 

 

다음에 해야할 일

 

각종 UI 제작