Dev./UE 언리얼 엔진

[TIL_250226] 언리얼 엔진 사운드 이펙트 구현: 무기 장전 & 엘리베이터 트리거

raindrovvv 2025. 2. 26. 23:10

💭회고

🗺️마인드맵

📒학습 내용

1. 사운드 구현: 무기 재장전 및 엘리베이터 트리거

1.1 무기 재장전 사운드 구현

핵심 요약:
무기 타입에 따라 장전 사운드를 조건적으로 재생한다.
라이플과 피스톨일 때만 GunReloadCue가 활성화된다.
  • 무기 타입 확인: EWeaponType Enum을 활용해 무기 종류를 구분한다.
    • Enum (열거형): 무기 타입을 구분하는 태그 역할 (`EWeaponType`)
    • 델리게이트: 상태 변화를 다른 시스템에 알리는 신호 (예: 무기 변경 시 UI 업데이트) 
      • Rifle과 Pistol일 때만 장전 사운드를 재생한다.
      • Knife나 미장착 상태에서는 사운드가 재생되지 않도록 설정한다.
  • 코드 구현: UCWeaponComponent의 Reload() 함수에 조건문을 추가하여, 무기가 라이플 또는 피스톨일 때만 사운드를 재생하도록 한다.
    • 아래 코드는 C++에서 사운드 큐(GunReloadCue)를 재생하는 예시이다.
void UCWeaponComponent::Reload()
{
    if (GetCurrentWeapon() == nullptr)
        return;  // 무기가 없으면 실행하지 않는다.

    // 무기가 라이플 또는 피스톨일 때만 사운드 재생 조건을 충족한다.
    if (Type == EWeaponType::Rifle || Type == EWeaponType::Pistol)
    {
        if (GunReloadCue)
        {
            UGameplayStatics::PlaySoundAtLocation(
                GetWorld(),
                GunReloadCue,
                Owner->GetActorLocation(),
                FRotator::ZeroRotator,
                1.0f, // 볼륨 설정
                1.0f, // 피치 설정
                0.0f  // 음량 감쇠 설정
            );
        }
        GetCurrentWeapon()->Reload();  // 무기 재장전 로직을 실행한다.
    }
    else
    {
        UE_LOG(LogTemp, Log, TEXT("Cannot reload: Only Rifle or Pistol can reload."));
        // 칼이나 무기 없음 상태에서는 재장전 로직을 실행하지 않는다.
    }
}

 

1.2 블루프린트 구현 가이드

  • 블루프린트 활용: C++ 대신 블루프린트에서 동일한 로직을 구현할 수 있다--한다.
  • 절차:
    1. UCWeaponComponent의 Reload() 함수를 BlueprintCallable로 설정하여 블루프린트에서 호출 가능하도록 한다.
    2. 입력 이벤트(예, EnhancedInputAction IA_Reload)에서 무기 타입을 확인한 후, 라이플 또는 피스톨일 때 Play Sound at Location 노드를 사용해 재장전 사운드를 재생한다.
    3. 이후 Reload() 노드를 호출해 무기 재장전 로직을 실행한다.

2. 엘리베이터 트리거 구현

엘리베이터 트리거 구현은 게임의 레벨 전환 시, 사운드가 끊기지 않고 자연스럽게 진행되도록 하고 싶었다. 트리거 오버랩 시 사운드를 재생하고, 사운드 재생이 완료된 후 레벨 전환을 진행되게 하면 소리가 씹히지 않는다...!

2.1 문제 상황과 해결 방법 🐞

  • 문제 상황: 단순히 트리거 오버랩 시 사운드를 재생하면, 레벨 전환으로 인해 사운드가 중간에 끊기는 문제가 발생한다.
  • 해결 방법: 사운드의 재생 길이를 확인한 후, 해당 시간만큼 딜레이를 주고 레벨 전환을 실행한다.
  • 주요 구현 포인트:
    • 플레이어 캐릭터 확인 후 입력을 제한하여 혼란을 방지한다.
    • ElevatorSound의 길이를 활용해 정확한 딜레이 타이머를 설정한다.

코드 : 아래 코드는 AAElevatorTrigger 클래스에서 트리거 오버랩 시 플레이어 캐릭터를 확인하고, 사운드 재생 후 레벨 전환을 딜레이와 함께 진행한다.

void AAElevatorTrigger::OnOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
    UPrimitiveComponent* OtherComp, int32 OtherBodyIndex,
    bool bFromSweep, const FHitResult& SweepResult)
{
    // 내가 만든 플레이어 캐릭터인지 확인
    ACPlayer* PlayerCharacter = Cast<ACPlayer>(OtherActor);
    if (!PlayerCharacter) return;

    if (ElevatorSound)
    {
        // 플레이어 입력 제한
        PlayerCharacter->DisableInput(Cast<APlayerController>(PlayerCharacter->GetController()));

        // ElevatorSound의 재생 길이 확인
        float SoundDuration = ElevatorSound->GetDuration();
        UGameplayStatics::PlaySound2D(this, ElevatorSound);

        // 트리거 타입에 따라 다음 레벨 상태 설정
        EGameState NewState = bIsN_Elevator ? EGameState::Labyrinth : EGameState::BossArea;
        FTimerHandle TimerHandle;
        GetWorld()->GetTimerManager().SetTimer(TimerHandle, [this, NewState]() {
            LoadNextLevel(NewState);
        }, SoundDuration, false);
    }
}

🖥️ 레벨 전환 함수 :

void AAElevatorTrigger::LoadNextLevel(EGameState NewState)
{
    ACGameState* GameState = GetWorld()->GetGameState<ACGameState>();
    if (GameState)
    {
        if (bIsN_Elevator)
        {
            UE_LOG(LogTemp, Warning, TEXT("N엘리베이터 선택 → 연구소 미로 이동"));
            GameState->SetGameState(EGameState::Labyrinth);
        }
        else
        {
            UE_LOG(LogTemp, Warning, TEXT("R엘리베이터 선택 → 보스 연구소 이동"));
            GameState->SetGameState(EGameState::BossArea);
        }
    }
}

🟣오늘의 옵시디언 현황