무한성이라고 불리던 스테이지를 일찍 탈출한 6명이서 사이드 프로젝트를 진행하기로 했다.
순전히 기능 공부를 위함이고 출시계획같은건 당연하게도 없다.
주제는 3D 뱀파이어 서바이벌이다.
개발 진행상황은 레포지토리 참조
-> 일신상의 이유로 Perforce로 변경
MVP 스팩을 크게 6가지로 나눴다.
스킬 / 캐릭터 / 적 / 시스템(웨이브, 스포너) / 아이템 / UI
나는 그 중 시스템(웨이브, 스포너)를 담당하게 됐다.
계획 중 하나였던 9기의 모든 프로젝트를 하나의 Organization으로 관리하고 각 다른 팀의 PR과 코드를 볼 수 있게 하고싶었는데 LFS 대역폭이 너무 적어서 어떤 대체제가 있을지 찾던 중
Perforce 라는 걸 알게됐다.
Perforce는 Git과 비슷한 형상관리툴인데 다른점은 Github같이 플랫폼이 있어서 거기서 관리하는게 아니라 개인 서버 혹은 클라우드 저장소를 연결해서 사용한다.
Perforce 사용법에 대해서는 나중에 다시한번 작성할 예정
#include "Gamemode/VampireSurvivalGamemode.h"
#include "EngineUtils.h"
#include "DataAsset/RunConfigDataAsset.h"
#include "DataAsset/WaveDataAsset.h"
#include "Kismet/GameplayStatics.h"
#include "Spawner/EnemySpawner.h"
AVampireSurvivalGamemode::AVampireSurvivalGamemode()
{
}
void AVampireSurvivalGamemode::BeginPlay()
{
Super::BeginPlay();
AWorldSettings* WorldSettings = GetWorldSettings();
if (bUseDebugTimeAcceleration)
{
WorldSettings->SetTimeDilation(30.0f);
}
for (TActorIterator<AEnemySpawner> It(GetWorld()); It; ++It)
{
EnemySpawner = *It;
break;
}
StartRun();
}
void AVampireSurvivalGamemode::StartRun()
{
if (!RunConfig)
{
UE_LOG(LogTemp, Warning, TEXT("RunConfig is not set."));
return;
}
//Debug, Production duration set 및 판단
RunDurationSeconds = bUseDebugDuration
? RunConfig->DebugDurationSeconds
: RunConfig->ProductionDurationSeconds;
ElapsedTime = 0.f;
CurrentWave = nullptr;
CurrentWaveIndex = INDEX_NONE;
SetCurrentWave(FindWaveForElapsedTime(ElapsedTime));
GetWorldTimerManager().SetTimer(
RunTimerHandler,
this,
&AVampireSurvivalGamemode::UpdateRunTime,
1.f,
true
);
}
void AVampireSurvivalGamemode::UpdateRunTime()
{
ElapsedTime += 1.f;
OnRunElapsedTimeChanged.Broadcast(ElapsedTime);
if (ElapsedTime >= RunDurationSeconds)
{
EndRun();
return;
}
SetCurrentWave(FindWaveForElapsedTime(ElapsedTime));
}
void AVampireSurvivalGamemode::EndRun()
{
GetWorldTimerManager().ClearTimer(RunTimerHandler);
if (EnemySpawner)
{
EnemySpawner->StopSpawning();
}
// 게임 종료
SetGameCompletedState();
UE_LOG(LogTemp, Warning, TEXT("Run ended."));
}
UWaveDataAsset* AVampireSurvivalGamemode::FindWaveForElapsedTime(float InElapsedTime) const
{
if (!RunConfig)
{
return nullptr;
}
for (UWaveDataAsset* Wave : RunConfig->Waves)
{
if (!Wave)
{
continue;
}
if (InElapsedTime >= Wave->StartTime && InElapsedTime < Wave->EndTime)
{
return Wave;
}
}
return nullptr;
}
void AVampireSurvivalGamemode::SetCurrentWave(UWaveDataAsset* NewWave)
{
if (CurrentWave == NewWave)
{
return;
}
CurrentWave = NewWave;
if (!CurrentWave)
{
return;
}
CurrentWaveIndex = CurrentWave->WaveIndex;
UE_LOG(LogTemp, Warning, TEXT("Wave changed: %d"), CurrentWaveIndex);
if (EnemySpawner)
{
EnemySpawner->SetElapsedTime(ElapsedTime);
EnemySpawner->SetWaveData(CurrentWave);
EnemySpawner->StartSpawning();
}
}
void AVampireSurvivalGamemode::SetGameCompletedState()
{
AWorldSettings* WorldSettings = GetWorldSettings();
if (!bIsGameCompleted && ElapsedTime >= 1800.f)
{
bIsGameCompleted = true;
OnIsGameCompletedState.Broadcast(bIsGameCompleted);
UGameplayStatics::SetGamePaused(GetWorld(), true);
}
}