Protptype of a wave based, first person shooter game made in Unreal Engine 4
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
MechDefence/Private/MGameMode.cpp

171 lines
4.4 KiB

// Fill out your copyright notice in the Description page of Project Settings.
#include "MGameMode.h"
#include "Kismet/GameplayStatics.h"
#include "MPlayerController.h"
#include "EngineUtils.h"
#include "GameFramework/Character.h"
#include "MAICharacterBase.h"
#include "GameplayTagsManager.h"
#include "MHealthComponent.h"
AMGameMode::AMGameMode()
{
PrimaryActorTick.bCanEverTick = true;
PrimaryActorTick.TickInterval = 1.f;
WaveCount = 0;
LevelEndViewTargetBlendTime = 2.f;
TimeBetweenWaves = 60.f;
NumEnemiesKilled = 0;
MaxEnemiesInWave = 10;
MinEnemiesInWave = 3;
}
void AMGameMode::StartPlay()
{
Super::StartPlay();
PrepareForNextWave();
}
void AMGameMode::HandlePlayerKilled()
{
GameOver();
}
void AMGameMode::HandlePlayerVehicleDestroyed(AActor* Vehicle)
{
GameOver();
}
void AMGameMode::GameOver()
{
if(SpectatingViewPointClass)
{
TArray<AActor*> ReturnedActors;
UGameplayStatics::GetAllActorsOfClass(this, SpectatingViewPointClass, ReturnedActors);
AActor* NewViewTarget = nullptr;
if(ReturnedActors.Num() > 0)
{
NewViewTarget = ReturnedActors[0];
for(FConstPlayerControllerIterator It = GetWorld()->GetPlayerControllerIterator(); It; It++)
{
AMPlayerController* PC = Cast<AMPlayerController>(It->Get());
if(PC)
{
PC->SetViewTargetWithBlend(NewViewTarget, LevelEndViewTargetBlendTime, EViewTargetBlendFunction::VTBlend_Cubic);
PC->OnGameOver();
SetWaveState(EWaveState::GameOver);
}
}
}
}
}
void AMGameMode::LevelCompleted()
{
if(SpectatingViewPointClass)
{
TArray<AActor*> ReturnedActors;
UGameplayStatics::GetAllActorsOfClass(this, SpectatingViewPointClass, ReturnedActors);
AActor* NewViewTarget = nullptr;
if(ReturnedActors.Num() > 0)
{
NewViewTarget = ReturnedActors[0];
for(FConstPlayerControllerIterator It = GetWorld()->GetPlayerControllerIterator(); It; It++)
{
AMPlayerController* PC = Cast<AMPlayerController>(It->Get());
if(PC)
{
PC->SetViewTargetWithBlend(NewViewTarget, LevelEndViewTargetBlendTime, EViewTargetBlendFunction::VTBlend_Cubic);
PC->OnLevelComplete();
SetWaveState(EWaveState::LevelComplete);
}
}
}
}
}
void AMGameMode::PrepareForNextWave()
{
GetWorldTimerManager().SetTimer(TimerHandle_NextWaveStart, this, &AMGameMode::StartWave, TimeBetweenWaves, false);
SetWaveState(EWaveState::WaitingToStart);
}
void AMGameMode::StartWave()
{
FTimerManager& TimerManager = GetWorldTimerManager();
// Cancel Timer if it is still active. This needs to be done if
// the wave is triggered manually by a console command to make sure wave isn't
// triggered twice
if(TimerManager.IsTimerActive(TimerHandle_NextWaveStart))
TimerManager.ClearTimer(TimerHandle_NextWaveStart);
WaveCount++;
NumEnemiesToSpawn = FMath::RandRange(MinEnemiesInWave, MaxEnemiesInWave);
NumEnemiesToSpawn = WaveCount * NumEnemiesToSpawn;
TimerManager.SetTimer(TimerHandle_EnemySpawn, this, &AMGameMode::SpawnEnemyTimerElapsed, 1.f, true, 0.f);
SetWaveState(EWaveState::WaveInProgress);
UE_LOG(LogTemp, Log, TEXT("Enemies to spawn %d"), NumEnemiesToSpawn);
}
void AMGameMode::EndWave()
{
GetWorldTimerManager().ClearTimer(TimerHandle_EnemySpawn);
SetWaveState(EWaveState::WaitingToComplete);
}
void AMGameMode::CheckWaveState()
{
bool IsPreparingForNextWave = GetWorldTimerManager().IsTimerActive(TimerHandle_NextWaveStart);
if(NumEnemiesToSpawn > 0 || IsPreparingForNextWave)
return;
bool IsAnyEnemyAlive = false;
for(TActorIterator<AMAICharacterBase> It(GetWorld()); It; ++It)
{
AMAICharacterBase* EnemyChar = *It;
if(EnemyChar->HasAllMatchingGameplayTags(SpawnedEnemyTags))
{
UMHealthComponent* HealthComponent = Cast<UMHealthComponent>(EnemyChar->GetComponentByClass(UMHealthComponent::StaticClass()));
if(HealthComponent && HealthComponent->GetHealth() > 0.f)
{
IsAnyEnemyAlive = true;
break;
}
}
}
if(!IsAnyEnemyAlive)
{
SetWaveState(EWaveState::WaveComplete);
PrepareForNextWave();
}
}
void AMGameMode::SetWaveState(EWaveState NewWaveState)
{
WaveStateChanged(NewWaveState, WaveState);
WaveState = NewWaveState;
}
void AMGameMode::SpawnEnemyTimerElapsed()
{
SpawnNewEnemy();
NumEnemiesToSpawn--;
if(NumEnemiesToSpawn <= 0)
{
EndWave();
}
}
void AMGameMode::Tick(float DeltaSeconds)
{
Super::Tick(DeltaSeconds);
CheckWaveState();
}