
Sound Mix 내에 각 Sound에 대한 Sound Class를 만들어서 Sound Class Effects의 index값으로 넣어준다.
이후 Sound의 Volume값을 조절하는 과정에서 Sound Class별로 조절이 가능하기에 프로젝트에 알맞게 Sound Class의 분류를 나누어 생성해준다.

이는 하나의 Sound Cue의 예시이다. 다음과 같이 원하는 Sound Cue를 선택하여 이에 맞는 Sound Class를 할당한다.
위처럼 세팅을 하게되면 에디터 내에서의 작업은 모두 완료되었다. 이를 활용하여 Widget의 Slider를 통해 Sound의 Volume을 조절해보고자 한다.
class THELASTSURVIVOR_API USoundOption : public UUserWidget
{
GENERATED_BODY()
protected:
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
class APlayerCharacter* Player;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
class USlider* BackgroundSoundSlider;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
class USlider* SoundEffectSlider;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
class USlider* PlayerSoundSlider;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
class UButton* AcceptButton;
float backgroundSound = 0;
float effectSound = 0;
float playerSound = 0;
UFUNCTION()
void BGSoundValue(float Value);
UFUNCTION()
void SoundEffectValue(float Value);
UFUNCTION()
void PlayerSoundValue(float Value);
UFUNCTION()
void ClickAcceptBtn();
virtual void NativeOnInitialized();
};
Player 내부에서 Widget을 통해 조절되는 Sound의 Volume값을 저장해두기 위해 Player 변수를 선언해두었다.
배경음, 효과음, 플레이어에 대한 각각의 Sound를 조절하기 위해 Slider를 3개 선언해두고 Accept 버튼을 선언하였다.
Slider와 버튼에서 사용자의 입력에 따라 호출되는 함수들 또한 선언하였고, 이는 UFUNCTION() 프로퍼티를 붙여서 선언해주어야 한다.
Super::NativeOnInitialized();
Player = Cast<APlayerCharacter>(GetOwningPlayerPawn());
BackgroundSoundSlider = Cast<USlider>(GetWidgetFromName(TEXT("BackgroundSlider")));
SoundEffectSlider = Cast<USlider>(GetWidgetFromName(TEXT("EffectSlider")));
PlayerSoundSlider = Cast<USlider>(GetWidgetFromName(TEXT("PlayerSlider")));
AcceptButton = Cast<UButton>(GetWidgetFromName(TEXT("AcceptBtn")));
if (Player) {
if (BackgroundSoundSlider) {
BackgroundSoundSlider->SetValue(Player->backgroundSound / 2);
backgroundSound = Player->backgroundSound;
BackgroundSoundSlider->OnValueChanged.AddDynamic(this, &USoundOption::BGSoundValue);
}
if (SoundEffectSlider) {
SoundEffectSlider->SetValue(Player->effectSound / 2);
effectSound = Player->effectSound;
SoundEffectSlider->OnValueChanged.AddDynamic(this, &USoundOption::SoundEffectValue);
}
if (PlayerSoundSlider) {
PlayerSoundSlider->SetValue(Player->playerSound / 2);
playerSound = Player->playerSound;
PlayerSoundSlider->OnValueChanged.AddDynamic(this, &USoundOption::PlayerSoundValue);
}
if (AcceptButton) {
AcceptButton->OnClicked.AddDynamic(this, &USoundOption::ClickAcceptBtn);
}
}
NativeOnInitialized() 함수는 기존의 UserWidget 클래스에 존재하는 함수이다. Widget이 생성될 때마다 호출되고, Widget의 Component를 초기화한다.
각각의 Component에서 해당하는 이벤트가 발생될 때마다 AddDynamic 매크로를 통해 지정해 둔 함수가 호출된다.
void USoundOption::BGSoundValue(float Value)
{
backgroundSound = Value;
}
void USoundOption::SoundEffectValue(float Value)
{
effectSound = Value;
}
void USoundOption::PlayerSoundValue(float Value)
{
playerSound = Value;
}
void USoundOption::ClickAcceptBtn()
{
BackgroundSoundSlider->SetValue(backgroundSound);
SoundEffectSlider->SetValue(effectSound);
PlayerSoundSlider->SetValue(playerSound);
Player->backgroundSound = backgroundSound * 2;
Player->effectSound = effectSound * 2;
Player->playerSound = playerSound * 2;
UGameplayStatics::SetSoundMixClassOverride(GetWorld(), Player->MainSoundMix, Player->SC_Background, backgroundSound * 2);
UGameplayStatics::SetSoundMixClassOverride(GetWorld(), Player->MainSoundMix, Player->SC_SoundEffect, effectSound * 2);
UGameplayStatics::SetSoundMixClassOverride(GetWorld(), Player->MainSoundMix, Player->SC_PlayerSound, playerSound * 2);
UGameplayStatics::PushSoundMixModifier(GetWorld(), Player->MainSoundMix);
RemoveFromParent();
}
Slider에서는 값이 바뀔 때마다 변수에 해당 값을 저장한다. 사용자가 값을 바꾼 뒤, 취소를 할 경우에는 이를 적용시키지 않아야 하기 때문이다.
Accept 버튼을 누를 경우, 각 Slider에 저장해둔 값으로 Value를 바꾸어준다.
UGameplayStatics 클래스에 내장되어 있는 SetSoundMixClassOverride() 함수를 통해 각 Sound Class의 Volume값을 사용자가 지정한 Slider의 Value값으로 지정해주고, PushSoundMixModifier() 함수를 통해 SoundMixClass에 해당 값들을 저장해준다.