This commit is contained in:
Antoine Caru 2025-03-14 13:35:51 +01:00
commit 5d3c61d590
31 changed files with 232 additions and 59 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
Content/Legumix/Levels/LVL_GYM_00.umap (Stored with Git LFS)

Binary file not shown.

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.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

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)
{
//Spawn sur une position
ALMEnemy* tempEnemy = GetWorld()->SpawnActor<ALMEnemy>(enemyToSpawn, spawnPosition->GetActorLocation(), FRotator::ZeroRotator);
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

@ -131,6 +131,11 @@ void ALMPlayer::SetWeaponManager(ULMWeaponManager* Manager)
void ALMPlayer::PlayAnimation(UAnimMontage* Animation)
{
UAnimInstance* AnimInstance = GetArms()->GetAnimInstance();
if (AnimInstance && Animation)
{
AnimInstance->Montage_Play(Animation);
}
}
void ALMPlayer::FireBullets(const FLMBulletInfo Settings)

View File

@ -29,10 +29,10 @@ void ALMRevolver::PrimaryFire()
}
return;
}
PlayEvent(FireEvent);
PlayAnimation(PrimaryFireAnimation);
Player->PlayAnimation(PrimaryFireArmsAnimation);
const FVector Origin = Player->GetWeaponFiringOrigin();
const FVector Direction = Player->GetAimVector();

View File

@ -77,7 +77,7 @@ void ALMWeaponBase::PlayEvent(UFMODEvent* Event) const
void ALMWeaponBase::PlayAnimation(UAnimMontage* Animation)
{
UAnimInstance* AnimInstance = WeaponMesh->GetAnimInstance();
if (Animation && AnimInstance)
{
AnimInstance->Montage_Play(Animation);

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(VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true"), Category = "Legumix")
TArray<ALMEnemy*> EnemyAliveList; // Liste des ennemis
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (AllowPrivateAccess = "true"), Category = "Legumix")
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
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (AllowPrivateAccess = "true"), Category = "Legumix")
float BreakTime; // Nombre d'ennemis dans la wave
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (AllowPrivateAccess = "true"), Category = "Legumix")
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;
};

View File

@ -85,11 +85,15 @@ protected: /* Weapon Data */
UPROPERTY(EditAnywhere, BlueprintReadWrite,Category="Legumix|Sounds")
TObjectPtr<UFMODEvent> EquipSound;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Legumix|Animations", meta=(AllowPrivateAccess=true))
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Legumix|Animations|Fire", meta=(AllowPrivateAccess=true))
TObjectPtr<UAnimMontage> PrimaryFireAnimation;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Legumix|Animations|Fire", meta=(AllowPrivateAccess=true))
TObjectPtr<UAnimMontage> PrimaryFireArmsAnimation;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Legumix|Animations", meta=(AllowPrivateAccess=true))
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Legumix|Animations|Reload", meta=(AllowPrivateAccess=true))
TObjectPtr<UAnimMontage> ReloadAnimation;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Legumix|Animations|Reload", meta=(AllowPrivateAccess=true))
TObjectPtr<UAnimMontage> ReloadArmsAnimation;
/** The number of seconds before being able to fire again. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Legumix|Weapon", meta=(AllowPrivateAccess=true))