Hey!

Working on a small wave based game where the player has to survive for as long as they can.

Basic idea is that the player spawns into the game and in 5 seconds the first enemy spawns, once that enemy is i killed after another 5 seconds more enemies spawn etc etc.

Right now ive got two variables in my C++ Header class (which are private - in bold):

Code:
  
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/GameModeBase.h"
#include "TPSGameMode.generated.h"

enum class EWaveState : uint8;

DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FOnActorKilled, AActor*, VictimActor, AActor*, KillerActor, AController*, KillerController);

UCLASS()
class TP_PROJECT_API ATPSGameMode : public AGameModeBase
{
    GENERATED_BODY()

protected:

    FTimerHandle TH_BotSpawn;

    FTimerHandle TH_NextWaveStart;

    // Number of bots to spawn in current wave
    int32 BotsToSpawn;

protected:

    // Allow BP to spawn a single bot
    UFUNCTION(BlueprintImplementableEvent, Category = "GameMode")
    void SpawnNewBot();

    void SpawnBotTimerElapsed();

    // Start spawning bots for wave
    void StartWave();

    // Stop spawning bots and end wave
    void EndWave();

    // set timer for next wave
    void PrepareNextWave();

    void CheckWaveState();

    void CheckPlayerState();

    void GameOver();

    void SetWaveState(EWaveState NewState);

private:

UPROPERTY(EditAnywhere, Category = "GameMode")
    float TimeBetweenWaves;

UPROPERTY(EditAnywhere, Category = "GameMode")
    int32 WaveCount;

public:

    ATPSGameMode();

    virtual void StartPlay() override;

    virtual void Tick(float DeltaSeconds);

    UPROPERTY(BlueprintAssignable, Category = "GameMode")
    FOnActorKilled OnActorKilled;
};
Im trying access them in my Widget BP that will have a count down timer and the current wave number.

Below is my CPP file for my GameMode:

Code:
#include "TPSGameMode.h"
#include "TimerManager.h"
#include "Engine/World.h"
#include "TPSHealthComponent.h"
#include "TPSPlayerState.h"
#include "TPSGameState.h"


ATPSGameMode::ATPSGameMode()
{
    TimeBetweenWaves = 5.0f;
    GameStateClass = ATPSGameState::StaticClass();
    PlayerStateClass = ATPSGameMode::StaticClass();

    PrimaryActorTick.bCanEverTick = true;
    PrimaryActorTick.TickInterval = 1.0f;
}

void ATPSGameMode::StartWave()
{
    WaveCount++;

    BotsToSpawn = 1 * WaveCount;

    GetWorldTimerManager().SetTimer(TH_BotSpawn, this, &ATPSGameMode::SpawnBotTimerElapsed, 1.0f, true, 0.0f);

    SetWaveState(EWaveState::WaveInProgress);
}

void ATPSGameMode::EndWave()
{
    GetWorldTimerManager().ClearTimer(TH_BotSpawn);
    SetWaveState(EWaveState::WaitingToComplete);
}

void ATPSGameMode::PrepareNextWave()
{
    GetWorldTimerManager().SetTimer(TH_NextWaveStart, this, &ATPSGameMode::StartWave, TimeBetweenWaves, false);
    SetWaveState(EWaveState::WaitingToStart);

}

void ATPSGameMode::CheckWaveState()
{
    bool bIsPrepForWave = GetWorldTimerManager().IsTimerActive(TH_NextWaveStart);

    if (BotsToSpawn > 0 || bIsPrepForWave)
    {
        return;
    }

    bool bIsAnyBotAlive = false;

    for (FConstPawnIterator ItPawns = GetWorld()->GetPawnIterator(); ItPawns; ++ItPawns)
    {
        APawn* TestPawn = ItPawns->Get();
        if (TestPawn == nullptr || TestPawn->IsPlayerControlled())
        {
            continue;
        }

        UTPSHealthComponent* HealthComponent = Cast<UTPSHealthComponent>(TestPawn->GetComponentByClass(UTPSHealthComponent::StaticClass()));
        if (HealthComponent && HealthComponent->GetHealth() > 0.0f)
        {
            bIsAnyBotAlive = true;
            break;
        }
    }

    if (!bIsAnyBotAlive)
    {
        SetWaveState(EWaveState::WaveComplete);
        PrepareNextWave();
    }
}

void ATPSGameMode::CheckPlayerState()
{
    for (FConstPlayerControllerIterator ItPlayer = GetWorld()->GetPlayerControllerIterator(); ItPlayer; ++ItPlayer)
    {
        APlayerController* PC = ItPlayer->Get();
        if (PC && PC->GetPawn())
        {
            APawn* MyPawn = PC->GetPawn();
            UTPSHealthComponent* HealthComponent = Cast<UTPSHealthComponent>(MyPawn->GetComponentByClass(UTPSHealthComponent::StaticClass()));
            if (ensure(HealthComponent) && HealthComponent->GetHealth() > 0.0f)
            {
                // Player is alive
                return;
            }
        }
    }

    // Player is dead
    GameOver();
}

void ATPSGameMode::GameOver()
{
    EndWave();
    SetWaveState(EWaveState::GameOver);
}

void ATPSGameMode::SetWaveState(EWaveState NewState)
{
    ATPSGameState* GS = GetGameState<ATPSGameState>();
    if (ensure(GS))
    {
        GS->SetWaveState(NewState);
    }
}

void ATPSGameMode::StartPlay()
{
    Super::StartPlay();
    PrepareNextWave();
}

void ATPSGameMode::Tick(float DeltaSeconds)
{
    Super::Tick(DeltaSeconds);

    CheckWaveState();
    CheckPlayerState();
}

void ATPSGameMode::SpawnBotTimerElapsed()
{
    SpawnNewBot();

    BotsToSpawn--;

    if (BotsToSpawn <=0)
    {
        EndWave();
    }
}
I also have a game state class that has an Enum and tracks the state of each wave:

Code:
// GameState.CPP

void ATPSGameState::OnWaveState(EWaveState OldState)
{
    WaveStateChanged(WaveState, OldState);
}

void ATPSGameState::SetWaveState(EWaveState NewState)
{
    EWaveState OldState = WaveState;
    WaveState = NewState;
    OnWaveState(OldState);
}
and

Code:
GameState.H

UENUM(BlueprintType)
enum class EWaveState : uint8 {
    WaitingToStart,

    WaveInProgress,

    // No longer spawning new bots
    WaitingToComplete,

    WaveComplete,

    GameOver,
};

UCLASS()
class TP_PROJECT_API ATPSGameState : public AGameStateBase
{
    GENERATED_BODY()

protected:

    UFUNCTION()
    void OnWaveState(EWaveState OldState);

    UFUNCTION(BlueprintImplementableEvent, Category = "GameState")
    void WaveStateChanged(EWaveState NewState, EWaveState OldState);

    UPROPERTY(BlueprintReadOnly, Category = "GameState")
    EWaveState WaveState;

public:

    void SetWaveState(EWaveState NewState);
};
Im stuck on how to access the WaveCount and the TimeBetweenWaves in my UI BP