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.
171 lines
4.4 KiB
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();
|
|
}
|
|
|
|
|