레벨 및 웨이브 시스템 구현과 실시간 HUD 업데이트(25.02.12)

Virus·2025년 2월 12일
0

1. 레벨 및 웨이브 시스템

게임에서 레벨과 웨이브를 관리하는 시스템을 구현하는 방법을 학습했습니다. 주요 구현 내용은 레벨이 시작될 때 웨이브를 초기화하고, 웨이브가 종료된 후 레벨을 종료하여 다음 레벨로 진행하는 것입니다.

레벨 시작 시 웨이브 초기화: StartLevel() 함수에서 레벨을 시작하고, 각 레벨마다 최대 웨이브 수를 설정하여 각 웨이브마다 아이템을 스폰하는 로직을 구현합니다.
웨이브 종료 후 레벨 종료: 각 웨이브가 종료되면 마지막 웨이브가 끝난 후 레벨을 종료하고, 다음 레벨로 넘어갑니다.
코드 예시:


void ASpartaGameState::StartLevel()
{
    UE_LOG(LogTemp, Warning, TEXT("레벨 %d 시작!"), CurrentLevelIndex + 1);

    // 웨이브 초기화
    CurrentWaveIndex = 0; // 새 레벨이 시작되면 웨이브 인덱스 초기화
    StartWave(); // 첫 번째 웨이브 시작
}

void ASpartaGameState::StartWave()
{
    UE_LOG(LogTemp, Warning, TEXT("Wave %d 시작!"), CurrentWaveIndex + 1);

    // 웨이브마다 아이템을 스폰하는 로직
    TArray<AActor*> FoundVolumes;
    UGameplayStatics::GetAllActorsOfClass(GetWorld(), ASpawnVolume::StaticClass(), FoundVolumes);

    // 웨이브별 아이템 개수 증가 (난이도 조정)
    int32 ItemsToSpawn = 10 + (CurrentWaveIndex * 5);
    UE_LOG(LogTemp, Warning, TEXT("스폰할 아이템 개수: %d"), ItemsToSpawn);

    if (FoundVolumes.Num() > 0)
    {
        ASpawnVolume* SpawnVolume = Cast<ASpawnVolume>(FoundVolumes[0]);
        if (SpawnVolume)
        {
            for (int32 i = 0; i < ItemsToSpawn; i++)
            {
                AActor* SpawnedActor = SpawnVolume->SpawnRandomItem();
                if (SpawnedActor && SpawnedActor->IsA(ACoinItem::StaticClass()))
                {
                    SpawnedCoinCount++; // 코인 수 증가
                }
            }
        }
    }

    // 웨이브 타이머 설정
    GetWorldTimerManager().SetTimer(
        WaveTimerHandle,
        this,
        &ASpartaGameState::EndWave,
        LevelDuration / MaxWaves, // 각 웨이브마다 일정 시간
        false
    );
}

void ASpartaGameState::EndWave()
{
    UE_LOG(LogTemp, Warning, TEXT("Wave %d 종료!"), CurrentWaveIndex + 1);

    CurrentWaveIndex++; // 웨이브 인덱스 증가

    if (CurrentWaveIndex >= MaxWaves)
    {
        // 마지막 웨이브가 끝나면 레벨 종료
        UE_LOG(LogTemp, Warning, TEXT("마지막 웨이브 완료, 레벨 종료 실행"));
        GetWorldTimerManager().SetTimer(
            EndLevelTimerHandle,
            this,
            &ASpartaGameState::EndLevel,
            2.0f, // 2초 후에 다음 레벨로 이동
            false
        );
    }
    else
    {
        // 웨이브가 남아 있으면 다음 웨이브 시작
        StartWave();
    }
}

void ASpartaGameState::EndLevel()
{
    // 레벨 종료 후, 다음 레벨로 진행
    UE_LOG(LogTemp, Warning, TEXT("레벨 %d 종료 후, %d번 레벨로 이동 중..."), CurrentLevelIndex + 1, CurrentLevelIndex + 2);

    // 게임 인스턴스를 통해 레벨 진행 상태 갱신
    if (UGameInstance* GameInstance = GetGameInstance())
    {
        USpartaGameInstance* SpartaGameInstance = Cast<USpartaGameInstance>(GameInstance);
        if (SpartaGameInstance)
        {
            AddScore(Score);  // 스코어 추가
            CurrentLevelIndex++;
            SpartaGameInstance->CurrentLevelIndex = CurrentLevelIndex;

            // 모든 레벨을 끝냈으면 게임 오버 처리
            if (CurrentLevelIndex >= MaxLevels)
            {
                OnGameOver();
                return;
            }

            // 새로운 레벨을 로드
            if (LevelMapNames.IsValidIndex(CurrentLevelIndex))
            {
                FName TargetMapName = LevelMapNames[CurrentLevelIndex];
                UGameplayStatics::OpenLevel(this, TargetMapName);
            }
        }
    }
}

2. HUD 업데이트

게임 내에서 실시간으로 정보를 표시하는 방법에 대해 배웠습니다. UpdateHUD() 함수에서 UTextBlock을 사용하여 현재 웨이브 번호와 코인 수 등을 HUD에 표시하고, 각 웨이브의 남은 시간도 실시간으로 업데이트하는 방법을 학습했습니다.

웨이브와 코인 수 표시: UTextBlock을 사용하여 현재 웨이브 번호와 코인 수를 HUD에 표시합니다.
타이머: GetWorldTimerManager().GetTimerRemaining()을 사용하여 각 웨이브의 남은 시간을 실시간으로 계산하고, HUD에 반영합니다.
코드 예시:


void ASpartaGameState::UpdateHUD()
{
    if (APlayerController* PlayerController = GetWorld()->GetFirstPlayerController())
    {
        if (ASpartaPlayerController* SpartaPlayerController = Cast<ASpartaPlayerController>(PlayerController))
        {
            if (UUserWidget* HUDWidget = SpartaPlayerController->GetHUDWidget())
            {
                // 웨이브 정보 표시
                if (UTextBlock* WaveText = Cast<UTextBlock>(HUDWidget->GetWidgetFromName(TEXT("Wave"))))
                {
                    WaveText->SetText(FText::FromString(FString::Printf(TEXT("Wave: %d/%d"), CurrentWaveIndex + 1, MaxWaves)));
                }

                // 코인 수 표시
                if (UTextBlock* CoinCountText = Cast<UTextBlock>(HUDWidget->GetWidgetFromName(TEXT("CoinCount"))))
                {
                    CoinCountText->SetText(FText::FromString(FString::Printf(TEXT("Coins: %d/%d"), CollectedCoinCount, SpawnedCoinCount)));
                }

                // 웨이브 남은 시간 표시
                if (UTextBlock* WaveTimeText = Cast<UTextBlock>(HUDWidget->GetWidgetFromName(TEXT("WaveTime"))))
                {
                    float RemainingWaveTime = GetWorldTimerManager().GetTimerRemaining(WaveTimerHandle);
                    WaveTimeText->SetText(FText::FromString(FString::Printf(TEXT("Wave Time: %.1f"), RemainingWaveTime)));
                }

                // 스코어 표시
                if (UTextBlock* ScoreText = Cast<UTextBlock>(HUDWidget->GetWidgetFromName(TEXT("Score"))))
                {
                    if (UGameInstance* GameInstance = GetGameInstance())
                    {
                        USpartaGameInstance* SpartaGameInstance = Cast<USpartaGameInstance>(GameInstance);
                        if (SpartaGameInstance)
                        {
                            ScoreText->SetText(FText::FromString(FString::Printf(TEXT("Score: %d"), SpartaGameInstance->TotalScore)));
                        }
                    }
                }

                // 레벨 표시
                if (UTextBlock* LevelIndexText = Cast<UTextBlock>(HUDWidget->GetWidgetFromName(TEXT("Level"))))
                {
                    LevelIndexText->SetText(FText::FromString(FString::Printf(TEXT("Level: %d"), CurrentLevelIndex + 1)));
                }
            }
        }
    }
}

요약

오늘 배운 주요 내용은 레벨 및 웨이브 관리와 HUD 업데이트였습니다. 레벨과 웨이브를 관리하는 로직을 통해 게임의 흐름을 제어하고, UTextBlock을 사용해 실시간으로 정보를 표시하여 게임 내 상태를 동적으로 업데이트하는 방법을 익혔습니다.

0개의 댓글

관련 채용 정보