Added : New wave managing system

This commit is contained in:
sSebster 2025-03-14 12:25:41 +01:00
parent 8064a47c2c
commit 2695d6c3e9
10 changed files with 182 additions and 27 deletions

BIN
Content/Legumix/Spawner/DT_WavePreset.uasset (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Content/Legumix/Spawner/LVL_TestSpawn.umap (Stored with Git LFS)

Binary file not shown.

View File

@ -0,0 +1,3 @@
#include "Enemy/LMEnemyRatio.h"
#include "Enemy/LMEnemy.h"

View File

@ -0,0 +1 @@
#include "LMWaveStructure.h"

View File

@ -16,7 +16,7 @@ ALMSpawnPosition::ALMSpawnPosition()
bool ALMSpawnPosition::CanSpawn() const
{
return !IsPlayerVisible();
return !IsPlayerVisible() && !IsOnCooldow;
}
// Called when the game starts or when spawned
@ -30,7 +30,7 @@ void ALMSpawnPosition::BeginPlay()
void ALMSpawnPosition::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
UE_LOG(LogTemp, Warning, TEXT("CanSpawn: %s"), CanSpawn() ? TEXT("true") : TEXT("false"));
//UE_LOG(LogTemp, Warning, TEXT("CanSpawn: %s"), CanSpawn() ? TEXT("true") : TEXT("false"));
}
bool ALMSpawnPosition::IsPlayerVisible() const
@ -54,15 +54,27 @@ bool ALMSpawnPosition::IsPlayerVisible() const
);
// Debug trace
DrawDebugLine(GetWorld(), Start, End, bHit ? FColor::Red : FColor::Green, false, 2.0f);
//DrawDebugLine(GetWorld(), Start, End, bHit ? FColor::Red : FColor::Green, false, 2.0f);
if (bHit)
{
UE_LOG(LogTemp, Warning, TEXT("LineTrace Hit: %s"), *HitResult.GetActor()->GetName());
//UE_LOG(LogTemp, Warning, TEXT("LineTrace Hit: %s"), *HitResult.GetActor()->GetName());
return HitResult.GetActor() == Player; // Retourne true uniquement si l'acteur touché est le joueur
}
UE_LOG(LogTemp, Warning, TEXT("LineTrace: No Hit"));
//UE_LOG(LogTemp, Warning, TEXT("LineTrace: No Hit"));
return false; // Aucun obstacle, le joueur est visible
}
void ALMSpawnPosition::StarCooldown()
{
IsOnCooldow = true;
GetWorld()->GetTimerManager().SetTimer(ProcessCooldown, this, &ALMSpawnPosition::EndCooldown, TimerCooldown, false);
}
void ALMSpawnPosition::EndCooldown()
{
IsOnCooldow = false;
}

View File

@ -1,6 +1,9 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "LMWaveManager.h"
#include "IPropertyTable.h"
#include "Components/CapsuleComponent.h"
#include "Enemy/LMEnemy.h"
// Sets default values
@ -18,16 +21,40 @@ void ALMWaveManager::BeginPlay()
StartWave();
}
void ALMWaveManager::SpawnEnemy(ALMSpawnPosition* spawnPosition, TSubclassOf<ALMEnemy> enemyToSpawn)
void ALMWaveManager::SpawnEnemy(ALMSpawnPosition* spawnPosition)
{
int RandomIndex = FMath::RandRange(0, AllEnemyType.Num()-1);
while(EnemiesPerType[RandomIndex] <= 0 )
{
RandomIndex = FMath::RandRange(0, AllEnemyType.Num()-1);
}
//Choisis un ennemis à spawn random
TSubclassOf<ALMEnemy> enemyToSpawn = AllEnemyType[RandomIndex];
//Spawn sur une position
FActorSpawnParameters SpawnParameters;
SpawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn;
ALMEnemy* tempEnemy = GetWorld()->SpawnActor<ALMEnemy>(enemyToSpawn, spawnPosition->GetActorLocation(), FRotator::ZeroRotator);
if (!tempEnemy)
{
UE_LOG(LogTemp, Error, TEXT("Failed to spawn enemy!"));
return;
}
spawnPosition->StarCooldown();
float tailleCapsule = tempEnemy->GetCapsuleComponent()->GetScaledCapsuleHalfHeight();
FVector newPosition = tempEnemy->GetActorLocation();
tempEnemy->SetActorLocation(FVector(newPosition.X,newPosition.Y,newPosition.Z + tailleCapsule));
//ajoute l'ennemis à la liste des ennemis vivants
EnemyAliveList.Add(tempEnemy);
//bind la method ennemydead à la death de l'ennemis
tempEnemy->OnEnemyDeath.AddUniqueDynamic(this, &ALMWaveManager::EnemyDead);
tempEnemy->OnEnemyDeath.AddDynamic(this, &ALMWaveManager::EnemyDead);
UE_LOG(LogTemp, Error, TEXT("Succes to spawn and bind on death method"));
EnemySpawned++;
EnemiesPerType[RandomIndex]--;
}
void ALMWaveManager::EnemyDead(ALMEnemy* enemyToRemoveFromLife)
@ -39,8 +66,15 @@ void ALMWaveManager::EnemyDead(ALMEnemy* enemyToRemoveFromLife)
bool ALMWaveManager::RemainsEnemyToSpawn()
{
int TotalEnemies = 0;
for (int EnemyCount : EnemiesPerType)
{
TotalEnemies += EnemyCount;
}
bool stillToSpawn = TotalEnemies !=0;
bool no = EnemyAliveList.Num() < MaxEnemyInstantiate;
return EnemyNumberInWave != EnemySpawned && no;
return EnemyNumberInWave != EnemySpawned && no && stillToSpawn;
}
void ALMWaveManager::CheckForSpawnerOK()
@ -55,6 +89,54 @@ void ALMWaveManager::CheckForSpawnerOK()
}
}
void ALMWaveManager::GetRandomDataWaveRow()
{
TArray<FName> RowNames = WaveDatePreset->GetRowNames();
int RandomIndex = FMath::RandRange(0, RowNames.Num() - 1);;
FName WaveName = RowNames[RandomIndex];
CurrentWaveName = WaveName.ToString();
FLMWaveStructure* InfoWaveRow = WaveDatePreset->FindRow<FLMWaveStructure>(WaveName, "");
//InternalEnemyRatio = InfoWaveRow->WaveComposition;
EnemyNumberInWave = InfoWaveRow->EnemyCount;
MaxEnemyInstantiate = InfoWaveRow->MaxEnemyCount;
for (const FLMEnemyRatio& EnemyRatio : InfoWaveRow->WaveComposition)
{
// Ajoute chaque EnemyType à la liste
AllEnemyType.Add(EnemyRatio.EnemyType);
}
// Récupère les ratios (NbEnemy) et calcule leur somme
int32 TotalRatio = 0;
for (const FLMEnemyRatio& EnemyRatio : InfoWaveRow->WaveComposition)
{
TotalRatio += EnemyRatio.NbEnemy;
}
// Sécurité : Si le total est 0, évite la division par zéro
if (TotalRatio == 0) return;
// Répartit les ennemis proportionnellement
int32 RemainingEnemies = EnemyNumberInWave;
for (const FLMEnemyRatio& EnemyRatio : InfoWaveRow->WaveComposition)
{
// Calcul proportionnel arrondi
int32 Count = FMath::RoundToInt((float(EnemyRatio.NbEnemy) / TotalRatio) * EnemyNumberInWave);
EnemiesPerType.Add(Count);
RemainingEnemies -= Count;
}
// Ajuste les arrondis pour respecter exactement EnemyNumberInWave
for (int32 i = 0; i < RemainingEnemies; ++i)
{
EnemiesPerType[i % EnemiesPerType.Num()]++;
}
}
// Called every frame
void ALMWaveManager::Tick(float DeltaTime)
{
@ -66,7 +148,7 @@ void ALMWaveManager::Tick(float DeltaTime)
{
//Choose spawnpoint to spawn
int32 RandomIndex = FMath::RandRange(0, SpawnPositionsOK.Num() - 1);
SpawnEnemy(SpawnPositionsOK[RandomIndex],TypeOfEnemy);
SpawnEnemy(SpawnPositionsOK[RandomIndex]);
EnemySpawned++;
}
}
@ -81,5 +163,6 @@ void ALMWaveManager::Tick(float DeltaTime)
void ALMWaveManager::StartWave()
{
GetRandomDataWaveRow();
EnemySpawned = 0;
}

View File

@ -0,0 +1,17 @@
#pragma once
#include "LMEnemyRatio.generated.h"
class ALMEnemy;
USTRUCT(BlueprintType)
struct FLMEnemyRatio : public FTableRowBase
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Legumix")
TSubclassOf<ALMEnemy> EnemyType;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Legumix", meta = (ClampMin = 0))
int NbEnemy;
};

View File

@ -17,15 +17,22 @@ public:
// Méthode pour vérifier si le spawn est possible
bool CanSpawn() const;
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (AllowPrivateAccess = "true"), Category = "Legumix")
float TimerCooldown = 1.5;
void StarCooldown();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
virtual void EndCooldown();
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
private:
bool IsPlayerVisible() const;
FTimerHandle ProcessCooldown;
bool IsOnCooldow;
};

View File

@ -5,6 +5,7 @@
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "LMSpawnPosition.h"
#include "LMWaveStructure.h"
#include "LMWaveManager.generated.h"
class ALMEnemy;
@ -17,34 +18,45 @@ class LEGUMEMIX_API ALMWaveManager : public AActor
public:
// Sets default values for this actor's properties
ALMWaveManager();
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (AllowPrivateAccess = "true"), Category = "Legumix")
TArray<ALMEnemy*> EnemyAliveList; // Liste des ennemis
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true"), Category = "Legumix")
FString CurrentWaveName; // Name of the current wave
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (AllowPrivateAccess = "true"), Category = "Legumix")
TArray<ALMSpawnPosition*> SpawnPositionsList; // Liste des ennemis
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (AllowPrivateAccess = "true"), Category = "Legumix")
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true"), Category = "Legumix")
TArray<ALMEnemy*> EnemyAliveList; // Liste des ennemis
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true"), Category = "Legumix")
int EnemyNumberInWave; // Nombre d'ennemis dans la wave
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (AllowPrivateAccess = "true"), Category = "Legumix")
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true"), Category = "Legumix")
int MaxEnemyInstantiate; // Nombre d'ennemis max spawnés
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (AllowPrivateAccess = "true"), Category = "Legumix")
TSubclassOf<ALMEnemy> TypeOfEnemy; // Type d'ennemis to spawn
float BreakTime; // Nombre d'ennemis dans la wave
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (AllowPrivateAccess = "true"), Category = "Legumix")
float BreakTime; // Nombre d'ennemis dans la wave
UDataTable* WaveDatePreset;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Legumix")
TArray<TSubclassOf<ALMEnemy>> AllEnemyType;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Legumix")
TArray<int> EnemiesPerType;
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
virtual void StartWave();
virtual void SpawnEnemy(ALMSpawnPosition* spawnPosition, TSubclassOf<ALMEnemy> enemyToSpawn);
virtual void SpawnEnemy(ALMSpawnPosition* spawnPosition);
UFUNCTION()
virtual void EnemyDead(ALMEnemy* enemyToRemoveFromLife);
virtual bool RemainsEnemyToSpawn();
virtual void CheckForSpawnerOK();
virtual void GetRandomDataWaveRow();
public:
// Called every frame
@ -52,7 +64,7 @@ public:
private:
TArray<ALMSpawnPosition*> SpawnPositionsOK;
int EnemySpawned;
int EnemySpawned = 0;
FTimerHandle BreakTimer;
};

View File

@ -0,0 +1,17 @@
#pragma once
#include "Enemy/LMEnemyRatio.h"
#include "LMWaveStructure.generated.h"
USTRUCT(BlueprintType)
struct FLMWaveStructure : public FTableRowBase
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Legumix")
TArray<FLMEnemyRatio> WaveComposition;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Legumix", meta = (ClampMin = 0))
int EnemyCount;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Legumix", meta = (ClampMin = 0))
int MaxEnemyCount;
};