PART 05 · 강의 3/3

음악 상태 머신

게임 상태와 음악 상태를 연결하는 상태 머신 설계 및 Blueprint/C++ 구현

01

음악 상태 머신 설계

게임 상태와 음악 상태를 매핑하는 아키텍처

음악 상태 머신은 게임의 상태(탐험, 전투, 대화 등)를 음악 상태에 매핑하고, 상태 전환 시 적절한 트랜지션을 수행하는 시스템입니다.

Music State Machine
Silence
Exploration
Combat

        ↓             ↓          ↓
Stealth
  
Boss
  
Victory / Defeat

상태 전환 매트릭스

From \ ToExplorationCombatStealthBoss
Exploration - 마디 경계 + 스팅어 페이드 2초 스팅어 + 즉시
Combat 마디 경계 + 페이드 - 마디 경계 스팅어 + 크로스페이드
Stealth 페이드 3초 스팅어 + 즉시 - 스팅어 + 즉시
Boss Victory 전환 구간 - - -
02

C++ Music Manager 구현

음악 상태 머신의 C++ 핵심 구현

C++ - Music State Manager
// 음악 상태 열거형 UENUM(BlueprintType) enum class EMusicState : uint8 { None, Exploration, Combat, Stealth, Boss, Victory, Defeat }; // 음악 상태 데이터 USTRUCT(BlueprintType) struct FMusicStateData { GENERATED_BODY() UPROPERTY(EditAnywhere) TArray<USoundBase*> Stems; UPROPERTY(EditAnywhere) float BPM = 120.0f; UPROPERTY(EditAnywhere) TArray<float> DefaultStemVolumes; }; // 상태 전환 함수 void UMusicManager::TransitionToState( EMusicState NewState) { if (NewState == CurrentState) return; EMusicState OldState = CurrentState; CurrentState = NewState; // 상태별 트랜지션 로직 const FMusicStateData& NewData = MusicStateMap[NewState]; // 1) Quartz 클럭의 다음 마디에 맞춰 전환 예약 FQuartzQuantizationBoundary Boundary; Boundary.Quantization = EQuartzCommandQuantization::Bar; // 2) 현재 스템 페이드 아웃 for (UAudioComponent* Stem : ActiveStems) { Stem->FadeOut(1.0f, 0.0f); } // 3) 새 스템을 양자화 재생 ActiveStems.Empty(); for (int32 i = 0; i < NewData.Stems.Num(); ++i) { UAudioComponent* StemComp = UGameplayStatics::SpawnSound2D( this, NewData.Stems[i]); StemComp->SetVolumeMultiplier( NewData.DefaultStemVolumes[i]); StemComp->PlayQuantized( GetWorld(), ClockHandle, Boundary, FOnQuartzCommandEventBP()); ActiveStems.Add(StemComp); } }
03

게임플레이 연동

게임 이벤트로 음악 상태 전환을 트리거하기

C++ - 게임 이벤트와 음악 연동
// 전투 시스템에서 음악 상태 변경 void ACombatManager::OnCombatStarted() { MusicManager->TransitionToState( EMusicState::Combat); MusicManager->PlayStinger( EMusicStingerType::EnemyDetected); } void ACombatManager::OnCombatEnded() { // 전투 종료 후 일정 딜레이를 두고 탐험 음악으로 복귀 GetWorldTimerManager().SetTimer( MusicTransitionTimer, [this]() { MusicManager->TransitionToState( EMusicState::Exploration); }, 3.0f, // 3초 후 전환 false ); } // 보스전 진입 void ABossArena::OnBossEncounterBegin() { MusicManager->TransitionToState( EMusicState::Boss); MusicManager->PlayStinger( EMusicStingerType::BossAppear); } // 보스 처치 void ABossArena::OnBossDefeated() { MusicManager->TransitionToState( EMusicState::Victory); }
전투 강도 기반 동적 믹싱

단순한 Combat/Explore 이진 분류보다, 전투 강도(0.0~1.0)를 실시간으로 계산하여 스템 볼륨에 반영하면 더 세밀한 적응형 음악이 됩니다. 적 수, 거리, 체력 비율 등을 종합하여 Intensity를 계산하세요.

04

MetaSounds와 Quartz 연동

MetaSounds 내부에서 Quartz 클럭 활용하기

MetaSounds는 Quartz와의 직접 연동을 지원합니다. MetaSound 그래프 내부에서 Quartz 이벤트를 수신하고, 비트에 동기화된 절차적 음악을 생성할 수 있습니다.

MetaSound + Quartz Integration
Quartz On Beat
Trigger Select (비트별 패턴)
Wave Player (드럼 샘플)
Audio Out
Input: BPM
Trigger Repeat (BPM 기반 간격)
Arpeggiator 트리거
MetaSounds 기반 절차적 음악

MetaSounds의 오실레이터 + Quartz 비트 동기화를 결합하면, 코드 없이 에디터에서 절차적 음악을 디자인할 수 있습니다. 아르페지에이터, 시퀀서, 드럼 머신 등을 MetaSound 그래프로 구현하는 것이 가능합니다.

SUMMARY

핵심 요약

  • 음악 상태 머신으로 게임 상태(탐험, 전투 등)와 음악 상태를 체계적으로 매핑한다
  • 상태 전환 매트릭스로 각 전환에 적합한 트랜지션 방식을 정의한다
  • 게임 이벤트(전투 시작, 보스 등장 등)에 연동하여 자연스러운 음악 전환을 구현한다
  • MetaSounds와 Quartz를 결합하여 절차적 음악(아르페지에이터, 시퀀서)을 구현할 수 있다
  • 전투 강도 값을 실시간으로 계산하여 스템 볼륨에 반영하면 더 세밀한 적응형 음악이 된다
PRACTICE

도전 과제

배운 내용을 직접 실습해보세요

실습 1: 블루프린트 음악 상태 관리

Enum으로 음악 상태(Explore, Combat, Stealth, Boss)를 정의하고, 상태 전환 시 적절한 음악 트랙을 크로스페이드로 전환하는 블루프린트 시스템을 구현하세요. FadeIn/FadeOut 시간은 상태별로 다르게 설정하세요.

실습 2: 전투 인텐시티 기반 음악 전환

전투 인텐시티(0.0~1.0)를 계산하는 시스템을 만들고, 인텐시티 구간별(Low, Medium, High)로 음악 레이어를 추가/제거하세요. 적 수, 거리, 플레이어 체력을 종합하여 인텐시티를 산출하세요.

심화 과제: 데이터 드리븐 음악 전환 시스템

Data Table로 음악 상태 전환 규칙(소스 상태, 대상 상태, 크로스페이드 시간, 스팅거 에셋, 전환 조건)을 정의하고, 이를 기반으로 동작하는 데이터 드리븐 음악 매니저를 구현하세요.