[Unreal_C++_DarkSoul]#18_Sound
Sound를 구현합니다.
Overview
- 개요 및 설계
- 코드
- 영상
#1. 개요 및 설계
1. 개요
- 게임 플레이에 필요한 사운드 이펙트들을 재생하기 위해 Sound 클래스를 구현합니다.
- Sound 객체는 월드 어느 곳에서도 배경 음악을 재생합니다.
- Sound 객체는 캐릭터의 자연스러운 행동 연출을 위한 사운드 이펙트를 재생합니다.
- Event Queue 디자인 패턴을 적용해 사운드 재생 요청과 처리 시점을 디커플링 합니다. 이러한 비동기 처리를 통해 다음 이벤트 처리가 블로킹되어 시스템 성능에 영향을 끼치는 것을 방지하고, 이벤트 처리 순서를 더 안정적으로 관리할 수 있으며, Sound 객체와 여타 사운드 재생 요청을 보내는 객체들 간의 커플링을 감소시킵니다.
2. 설계
- 먼저, Sound 클래스를 정의합니다. Sound 클래스는 다른 객체로 부터 전달받은 SoundCue 형식의 데이터를 Sound Event Queue에 차례대로 삽입합니다.
- 다음으로, Sound 클래스를 상속하는 BGSound 클래스를 정의합니다. BGSound 클래스는 현재 재생하고 있는 배경 음악 재생 시간이 끝나면 Event Queue의 마지막 위치에 다시 삽입합니다. 그리고, 다음 배경 음악을 자동적으로 재생합니다.
- 마지막으로, Sound 클래스를 상속하는 EffectSound 클래스를 정의합니다. Effect 클래스는 World 내 다른 객체들로 부터 SoundCue 형식의 데이터를 전달받아 Event Queue에 차례대로 삽입하고 가장 먼저 들어온 SoundCue부터 차례대로 재생합니다.
#1. 코드
1. Sound 클래스
#include "Sound.h"
#include "Global/Global.h"
ASound::ASound()
{
PrimaryActorTick.bCanEverTick = true;
}
void ASound::BeginPlay()
{
Super::BeginPlay();
}
void ASound::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void ASound::PlaySoundAtLocation(USoundCue* InSoundCue, const AActor* InActor)
{
if (!!InSoundCue && !!InActor)
{
UGameplayStatics::PlaySoundAtLocation(
InActor->GetWorld(),
InSoundCue,
InActor->GetActorLocation()
);
}
}
// [23-06-30] Sound Event Queue
/* ************************************************************************
목적:
Human Sound와 Weapon Sound를 Audio Component로 부터 받아와 재생합니다.
설명:
InSoundCue1 = Human Sound
InSoundCue2 = Weapon Sound
* ************************************************************************/
void ASound::AddNewSoundCueToEventQueue(USoundCue* InSoundCue1, USoundCue* InSoundCue2,
const AActor* InActor1, const AActor* InActor2)
{
if (!!InSoundCue1 && !!InActor1)
{
QSoundEvents.Enqueue(MakeTuple(InSoundCue1, InActor1));
}
if (!!InSoundCue2 && !!InActor2)
{
QSoundEvents.Enqueue(MakeTuple(InSoundCue2, InActor2));
}
}
Details
- SoundCue 형식의 데이터가 특정 위치에서 재생되는 사운드일 경우 PlaySoundAtLocation를 호출합니다.
- 새로운 SoundCue를 전달 받았을 경우 AddNewSoundCueToEventQueue() 함수를 호출해 Event Queue의 마지막 위치에 해당 SoundCue를 삽입합니다.
2. BackgroundSound 클래스
#include "BackgroundSound.h"
#include "Global/Global.h"
#include "Components/AudioComponent.h"
ABackgroundSound::ABackgroundSound()
{}
void ABackgroundSound::BeginPlay()
{
Super::BeginPlay();
// #1. BG Sounds
if (SoundCues.Num() > 0)
{
for (const auto& SoundCue : SoundCues)
{
QBGSoundCues.Enqueue(SoundCue);
}
}
SpawnBGSoundCue();
}
void ABackgroundSound::SpawnBGSoundCue()
{
if (QBGSoundCues.IsEmpty() == false)
{
BGAudioComp = UGameplayStatics::SpawnSound2D(GetWorld(), *(QBGSoundCues.Peek()));
if (!!BGAudioComp)
{
BGAudioComp->OnAudioFinished.AddDynamic(this, &ABackgroundSound::OnBGSoundFinished);
BGAudioComp->bAutoDestroy = false;
}
else
{
PrintLine();
}
}
}
void ABackgroundSound::OnBGSoundFinished()
{
if (BGAudioComp != nullptr)
{
BGAudioComp->Stop();
USoundCue* PrevSoundCue;
if (QBGSoundCues.Dequeue(PrevSoundCue) && !QBGSoundCues.IsEmpty())
{
SpawnBGSoundCue();
QBGSoundCues.Enqueue(PrevSoundCue);
}
}
}
Details
- BackgroundSound 클래스는 게임 플레이 시작 전에 미리 설정한 배경 음악들을 게임 시작과 함께 Event Queue에 삽입합니다.
- UGameplayStatics가 제공하는 SpawnSound2D()를 통해 World에 배경 음악 SoundCue를 Spawn 합니다.
- 현재 재생되고 있는 배경 음악이 끝날 경우, OnBGSoundFinished() 함수를 호출해서 해당 배경 음악의 재생을 정지하고, Event Queue의 다음 배경음악을 재생합니다.
3. EffectSound 클래스
#include "EffectSound.h"
#include "Global/Global.h"
#include "GameObjects/GameObject.h"
#include "ActorComponents/C_AudioComponent.h"
AEffectSound::AEffectSound()
{
}
void AEffectSound::BeginPlay()
{
Super::BeginPlay();
// [23-06-20] Event Queue
TArray<AActor*> Objects;
UGameplayStatics::GetAllActorsOfClass(GetWorld(), AGameObject::StaticClass(), Objects);
for (const auto& Object : Objects)
{
if (!!Object)
{
UC_AudioComponent* AudioComponent = Object->FindComponentByClass<UC_AudioComponent>();
if (!!AudioComponent)
{
AudioComponent->OnSendEffectSound.BindUFunction(this, "AddNewSoundCueToEventQueue");
}
}
}
}
void AEffectSound::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
// [23-06-30] Sound Event Queue
if (!QSoundEvents.IsEmpty())
{
PlaySoundAtLocation(QSoundEvents.Peek()->Get<0>(), QSoundEvents.Peek()->Get<1>());
QSoundEvents.Pop();
}
}
Details
- 월드 내 GameObject 형식의 객체들을 가져와서 이들이 갖는 Audio Comopnent가 선언한 OnSendEffectSound 델리게이트 함수와 AddNewSoundCueToEventQueue 함수를 동적 바인딩 합니다.
- Tick() 함수는 매 프레임마다 호출되는 함수로 Event Queue에 저장된 SoundCue 형식의 데이터를 차례대로 재생합니다.
#2. 영상
'개인프로젝트' 카테고리의 다른 글
[Unreal_C++_DarkSoul]#20_기능 구현, Level Sequence (0) | 2023.09.17 |
---|---|
[Unreal_C++_DarkSoul]#19_기능 구현, Portal (0) | 2023.07.23 |
[Unreal_C++_DarkSoul]#17_기능 구현, Grid 클래스 (0) | 2023.06.03 |
[Unreal_C++_DarkSoul]#16_문제 해결, 런 타임 AI 실행 여부 (0) | 2023.05.27 |
[Unreal_C++_DarkSoul]#15_문제 해결, Data Table 로드 함수 (1) | 2023.05.08 |