게임에서 레벨과 웨이브를 관리하는 시스템을 구현하는 방법을 학습했습니다. 주요 구현 내용은 레벨이 시작될 때 웨이브를 초기화하고, 웨이브가 종료된 후 레벨을 종료하여 다음 레벨로 진행하는 것입니다.
레벨 시작 시 웨이브 초기화: 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);
}
}
}
}
게임 내에서 실시간으로 정보를 표시하는 방법에 대해 배웠습니다. 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을 사용해 실시간으로 정보를 표시하여 게임 내 상태를 동적으로 업데이트하는 방법을 익혔습니다.