Make sure max enemies applies properly
This commit is contained in:
@@ -138,183 +138,41 @@ void ASpaceShooterGameMode::SpawnEnemy()
|
|||||||
|
|
||||||
void ASpaceShooterGameMode::SpawnEnemyWave()
|
void ASpaceShooterGameMode::SpawnEnemyWave()
|
||||||
{
|
{
|
||||||
UWorld* World = GetWorld();
|
// Count current enemies
|
||||||
if (!World || !EnemyClass)
|
TArray<AActor*> FoundEnemies;
|
||||||
return;
|
UGameplayStatics::GetAllActorsOfClass(GetWorld(), AEnemySpaceship::StaticClass(), FoundEnemies);
|
||||||
|
|
||||||
// Choose a random direction for the wave
|
// Only spawn if we haven't reached the maximum
|
||||||
float WaveAngle = FMath::RandRange(0.0f, 2.0f * PI);
|
if (FoundEnemies.Num() < MaxEnemies)
|
||||||
FVector2D EdgeDirection(FMath::Cos(WaveAngle), FMath::Sin(WaveAngle));
|
|
||||||
|
|
||||||
// Get player location for facing direction
|
|
||||||
FVector PlayerLocation = GetPlayerLocation();
|
|
||||||
|
|
||||||
// Get screen bounds
|
|
||||||
TArray<FVector2D> ScreenBounds = GetScreenBounds();
|
|
||||||
float ScreenWidth = ScreenBounds[1].X - ScreenBounds[0].X;
|
|
||||||
|
|
||||||
// Create a line of enemies perpendicular to the direction
|
|
||||||
FVector2D PerpDirection(-EdgeDirection.Y, EdgeDirection.X);
|
|
||||||
|
|
||||||
// Spawn wave of enemies - increased distance from 2000 to MinimumSpawnDistance
|
|
||||||
for (int32 i = 0; i < WaveSize; i++)
|
|
||||||
{
|
{
|
||||||
FVector ProposedLocation;
|
|
||||||
ProposedLocation.X = PlayerLocation.X + (EdgeDirection.X * MinimumSpawnDistance) +
|
|
||||||
(PerpDirection.X * (i - WaveSize / 2) * FormationSpacing);
|
|
||||||
ProposedLocation.Y = PlayerLocation.Y + (EdgeDirection.Y * MinimumSpawnDistance) +
|
|
||||||
(PerpDirection.Y * (i - WaveSize / 2) * FormationSpacing);
|
|
||||||
ProposedLocation.Z = PlayerLocation.Z;
|
|
||||||
|
|
||||||
// Ensure the spawn location is far enough from the player
|
UWorld* World = GetWorld();
|
||||||
FVector SpawnLocation = EnsureMinimumSpawnDistance(ProposedLocation, PlayerLocation);
|
if (!World || !EnemyClass)
|
||||||
|
return;
|
||||||
|
|
||||||
FRotator SpawnRotation = FRotator::ZeroRotator;
|
// Choose a random direction for the wave
|
||||||
FActorSpawnParameters SpawnParams;
|
float WaveAngle = FMath::RandRange(0.0f, 2.0f * PI);
|
||||||
SpawnParams.SpawnCollisionHandlingOverride =
|
FVector2D EdgeDirection(FMath::Cos(WaveAngle), FMath::Sin(WaveAngle));
|
||||||
ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn;
|
|
||||||
|
|
||||||
AEnemySpaceship* NewEnemy = World->SpawnActor<AEnemySpaceship>(
|
// Get player location for facing direction
|
||||||
EnemyClass, SpawnLocation, SpawnRotation, SpawnParams);
|
FVector PlayerLocation = GetPlayerLocation();
|
||||||
|
|
||||||
if (NewEnemy)
|
// Get screen bounds
|
||||||
|
TArray<FVector2D> ScreenBounds = GetScreenBounds();
|
||||||
|
float ScreenWidth = ScreenBounds[1].X - ScreenBounds[0].X;
|
||||||
|
|
||||||
|
// Create a line of enemies perpendicular to the direction
|
||||||
|
FVector2D PerpDirection(-EdgeDirection.Y, EdgeDirection.X);
|
||||||
|
|
||||||
|
// Spawn wave of enemies - increased distance from 2000 to MinimumSpawnDistance
|
||||||
|
for (int32 i = 0; i < WaveSize; i++)
|
||||||
{
|
{
|
||||||
RotateTowardsPlayer(NewEnemy, PlayerLocation);
|
FVector ProposedLocation;
|
||||||
}
|
ProposedLocation.X = PlayerLocation.X + (EdgeDirection.X * MinimumSpawnDistance) +
|
||||||
}
|
(PerpDirection.X * (i - WaveSize / 2) * FormationSpacing);
|
||||||
|
ProposedLocation.Y = PlayerLocation.Y + (EdgeDirection.Y * MinimumSpawnDistance) +
|
||||||
// Increase wave counter and possibly switch back to random
|
(PerpDirection.Y * (i - WaveSize / 2) * FormationSpacing);
|
||||||
CurrentWaveCount++;
|
ProposedLocation.Z = PlayerLocation.Z;
|
||||||
if (CurrentWaveCount >= 3)
|
|
||||||
{
|
|
||||||
CurrentPattern = ESpawnPattern::Random;
|
|
||||||
CurrentWaveCount = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASpaceShooterGameMode::SpawnEnemyFormation()
|
|
||||||
{
|
|
||||||
UWorld* World = GetWorld();
|
|
||||||
if (!World || !EnemyClass)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Get player location
|
|
||||||
FVector PlayerLocation = GetPlayerLocation();
|
|
||||||
|
|
||||||
// Select a formation type (0 = V-formation, 1 = Line, 2 = Diamond)
|
|
||||||
int32 FormationType = FMath::RandRange(0, 2);
|
|
||||||
|
|
||||||
// Choose a random approach angle
|
|
||||||
float ApproachAngle = FMath::RandRange(0.0f, 2.0f * PI);
|
|
||||||
FVector2D ApproachDir(FMath::Cos(ApproachAngle), FMath::Sin(ApproachAngle));
|
|
||||||
|
|
||||||
// Base spawn position far from player - increased from 2500 to MinimumSpawnDistance + 500
|
|
||||||
FVector BaseSpawnPos = PlayerLocation + FVector(ApproachDir.X, ApproachDir.Y, 0) * (MinimumSpawnDistance + 500.0f);
|
|
||||||
|
|
||||||
// Create formation positions
|
|
||||||
TArray<FVector> FormationPositions;
|
|
||||||
|
|
||||||
switch (FormationType)
|
|
||||||
{
|
|
||||||
case 0: // V-formation
|
|
||||||
for (int32 i = 0; i < 5; i++)
|
|
||||||
{
|
|
||||||
if (i == 0) // Leader
|
|
||||||
{
|
|
||||||
FormationPositions.Add(BaseSpawnPos);
|
|
||||||
}
|
|
||||||
else if (i % 2 == 1) // Left wing
|
|
||||||
{
|
|
||||||
FVector Offset(-ApproachDir.Y, ApproachDir.X, 0);
|
|
||||||
FormationPositions.Add(BaseSpawnPos + Offset * FormationSpacing * ((i + 1) / 2));
|
|
||||||
}
|
|
||||||
else // Right wing
|
|
||||||
{
|
|
||||||
FVector Offset(ApproachDir.Y, -ApproachDir.X, 0);
|
|
||||||
FormationPositions.Add(BaseSpawnPos + Offset * FormationSpacing * (i / 2));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1: // Line formation
|
|
||||||
for (int32 i = 0; i < 5; i++)
|
|
||||||
{
|
|
||||||
FVector2D PerpDir(-ApproachDir.Y, ApproachDir.X);
|
|
||||||
FVector Offset(PerpDir.X, PerpDir.Y, 0);
|
|
||||||
FormationPositions.Add(BaseSpawnPos + Offset * FormationSpacing * (i - 2));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2: // Diamond formation
|
|
||||||
FormationPositions.Add(BaseSpawnPos); // Center
|
|
||||||
|
|
||||||
FVector2D PerpDir(-ApproachDir.Y, ApproachDir.X);
|
|
||||||
|
|
||||||
// Top
|
|
||||||
FormationPositions.Add(BaseSpawnPos + FVector(ApproachDir.X, ApproachDir.Y, 0) * FormationSpacing);
|
|
||||||
// Bottom
|
|
||||||
FormationPositions.Add(BaseSpawnPos - FVector(ApproachDir.X, ApproachDir.Y, 0) * FormationSpacing);
|
|
||||||
// Left
|
|
||||||
FormationPositions.Add(BaseSpawnPos + FVector(PerpDir.X, PerpDir.Y, 0) * FormationSpacing);
|
|
||||||
// Right
|
|
||||||
FormationPositions.Add(BaseSpawnPos - FVector(PerpDir.X, PerpDir.Y, 0) * FormationSpacing);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Spawn enemies at formation positions
|
|
||||||
for (const FVector& Position : FormationPositions)
|
|
||||||
{
|
|
||||||
// Ensure the spawn location is far enough from the player
|
|
||||||
FVector SpawnLocation = EnsureMinimumSpawnDistance(Position, PlayerLocation);
|
|
||||||
|
|
||||||
FRotator SpawnRotation = FRotator::ZeroRotator;
|
|
||||||
FActorSpawnParameters SpawnParams;
|
|
||||||
SpawnParams.SpawnCollisionHandlingOverride =
|
|
||||||
ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn;
|
|
||||||
|
|
||||||
AEnemySpaceship* NewEnemy = World->SpawnActor<AEnemySpaceship>(
|
|
||||||
EnemyClass, SpawnLocation, SpawnRotation, SpawnParams);
|
|
||||||
|
|
||||||
if (NewEnemy)
|
|
||||||
{
|
|
||||||
RotateTowardsPlayer(NewEnemy, PlayerLocation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Switch back to random pattern after a formation spawn
|
|
||||||
CurrentPattern = ESpawnPattern::Random;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASpaceShooterGameMode::SpawnEnemyFlanking()
|
|
||||||
{
|
|
||||||
UWorld* World = GetWorld();
|
|
||||||
if (!World || !EnemyClass)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Get player location
|
|
||||||
FVector PlayerLocation = GetPlayerLocation();
|
|
||||||
|
|
||||||
// Spawn enemies from multiple sides (usually 2-3 sides)
|
|
||||||
int32 NumSides = FMath::RandRange(2, 3);
|
|
||||||
float BaseAngle = FMath::RandRange(0.0f, 2.0f * PI);
|
|
||||||
|
|
||||||
for (int32 Side = 0; Side < NumSides; Side++)
|
|
||||||
{
|
|
||||||
// Calculate angle for this side
|
|
||||||
float Angle = BaseAngle + (Side * (2.0f * PI / NumSides));
|
|
||||||
FVector2D Direction(FMath::Cos(Angle), FMath::Sin(Angle));
|
|
||||||
|
|
||||||
// Spawn 1-2 enemies from this side
|
|
||||||
int32 NumEnemies = FMath::RandRange(1, 2);
|
|
||||||
|
|
||||||
for (int32 i = 0; i < NumEnemies; i++)
|
|
||||||
{
|
|
||||||
// Add some variation to the spawn position
|
|
||||||
float OffsetAngle = Angle + FMath::RandRange(-0.3f, 0.3f);
|
|
||||||
FVector2D OffsetDir(FMath::Cos(OffsetAngle), FMath::Sin(OffsetAngle));
|
|
||||||
|
|
||||||
// Increased from 2000 to MinimumSpawnDistance
|
|
||||||
FVector ProposedLocation = PlayerLocation + FVector(OffsetDir.X, OffsetDir.Y, 0) * MinimumSpawnDistance;
|
|
||||||
|
|
||||||
// Ensure the spawn location is far enough from the player
|
// Ensure the spawn location is far enough from the player
|
||||||
FVector SpawnLocation = EnsureMinimumSpawnDistance(ProposedLocation, PlayerLocation);
|
FVector SpawnLocation = EnsureMinimumSpawnDistance(ProposedLocation, PlayerLocation);
|
||||||
@@ -332,10 +190,179 @@ void ASpaceShooterGameMode::SpawnEnemyFlanking()
|
|||||||
RotateTowardsPlayer(NewEnemy, PlayerLocation);
|
RotateTowardsPlayer(NewEnemy, PlayerLocation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Return to random spawning
|
// Increase wave counter and possibly switch back to random
|
||||||
CurrentPattern = ESpawnPattern::Random;
|
CurrentWaveCount++;
|
||||||
|
if (CurrentWaveCount >= 3)
|
||||||
|
{
|
||||||
|
CurrentPattern = ESpawnPattern::Random;
|
||||||
|
CurrentWaveCount = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASpaceShooterGameMode::SpawnEnemyFormation()
|
||||||
|
{
|
||||||
|
// Count current enemies
|
||||||
|
TArray<AActor*> FoundEnemies;
|
||||||
|
UGameplayStatics::GetAllActorsOfClass(GetWorld(), AEnemySpaceship::StaticClass(), FoundEnemies);
|
||||||
|
|
||||||
|
// Only spawn if we haven't reached the maximum
|
||||||
|
if (FoundEnemies.Num() < MaxEnemies)
|
||||||
|
{
|
||||||
|
|
||||||
|
UWorld* World = GetWorld();
|
||||||
|
if (!World || !EnemyClass)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Get player location
|
||||||
|
FVector PlayerLocation = GetPlayerLocation();
|
||||||
|
|
||||||
|
// Select a formation type (0 = V-formation, 1 = Line, 2 = Diamond)
|
||||||
|
int32 FormationType = FMath::RandRange(0, 2);
|
||||||
|
|
||||||
|
// Choose a random approach angle
|
||||||
|
float ApproachAngle = FMath::RandRange(0.0f, 2.0f * PI);
|
||||||
|
FVector2D ApproachDir(FMath::Cos(ApproachAngle), FMath::Sin(ApproachAngle));
|
||||||
|
|
||||||
|
// Base spawn position far from player - increased from 2500 to MinimumSpawnDistance + 500
|
||||||
|
FVector BaseSpawnPos = PlayerLocation + FVector(ApproachDir.X, ApproachDir.Y, 0) * (MinimumSpawnDistance + 500.0f);
|
||||||
|
|
||||||
|
// Create formation positions
|
||||||
|
TArray<FVector> FormationPositions;
|
||||||
|
|
||||||
|
switch (FormationType)
|
||||||
|
{
|
||||||
|
case 0: // V-formation
|
||||||
|
for (int32 i = 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
if (i == 0) // Leader
|
||||||
|
{
|
||||||
|
FormationPositions.Add(BaseSpawnPos);
|
||||||
|
}
|
||||||
|
else if (i % 2 == 1) // Left wing
|
||||||
|
{
|
||||||
|
FVector Offset(-ApproachDir.Y, ApproachDir.X, 0);
|
||||||
|
FormationPositions.Add(BaseSpawnPos + Offset * FormationSpacing * ((i + 1) / 2));
|
||||||
|
}
|
||||||
|
else // Right wing
|
||||||
|
{
|
||||||
|
FVector Offset(ApproachDir.Y, -ApproachDir.X, 0);
|
||||||
|
FormationPositions.Add(BaseSpawnPos + Offset * FormationSpacing * (i / 2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1: // Line formation
|
||||||
|
for (int32 i = 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
FVector2D PerpDir(-ApproachDir.Y, ApproachDir.X);
|
||||||
|
FVector Offset(PerpDir.X, PerpDir.Y, 0);
|
||||||
|
FormationPositions.Add(BaseSpawnPos + Offset * FormationSpacing * (i - 2));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2: // Diamond formation
|
||||||
|
FormationPositions.Add(BaseSpawnPos); // Center
|
||||||
|
|
||||||
|
FVector2D PerpDir(-ApproachDir.Y, ApproachDir.X);
|
||||||
|
|
||||||
|
// Top
|
||||||
|
FormationPositions.Add(BaseSpawnPos + FVector(ApproachDir.X, ApproachDir.Y, 0) * FormationSpacing);
|
||||||
|
// Bottom
|
||||||
|
FormationPositions.Add(BaseSpawnPos - FVector(ApproachDir.X, ApproachDir.Y, 0) * FormationSpacing);
|
||||||
|
// Left
|
||||||
|
FormationPositions.Add(BaseSpawnPos + FVector(PerpDir.X, PerpDir.Y, 0) * FormationSpacing);
|
||||||
|
// Right
|
||||||
|
FormationPositions.Add(BaseSpawnPos - FVector(PerpDir.X, PerpDir.Y, 0) * FormationSpacing);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spawn enemies at formation positions
|
||||||
|
for (const FVector& Position : FormationPositions)
|
||||||
|
{
|
||||||
|
// Ensure the spawn location is far enough from the player
|
||||||
|
FVector SpawnLocation = EnsureMinimumSpawnDistance(Position, PlayerLocation);
|
||||||
|
|
||||||
|
FRotator SpawnRotation = FRotator::ZeroRotator;
|
||||||
|
FActorSpawnParameters SpawnParams;
|
||||||
|
SpawnParams.SpawnCollisionHandlingOverride =
|
||||||
|
ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn;
|
||||||
|
|
||||||
|
AEnemySpaceship* NewEnemy = World->SpawnActor<AEnemySpaceship>(
|
||||||
|
EnemyClass, SpawnLocation, SpawnRotation, SpawnParams);
|
||||||
|
|
||||||
|
if (NewEnemy)
|
||||||
|
{
|
||||||
|
RotateTowardsPlayer(NewEnemy, PlayerLocation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switch back to random pattern after a formation spawn
|
||||||
|
CurrentPattern = ESpawnPattern::Random;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASpaceShooterGameMode::SpawnEnemyFlanking()
|
||||||
|
{
|
||||||
|
// Count current enemies
|
||||||
|
TArray<AActor*> FoundEnemies;
|
||||||
|
UGameplayStatics::GetAllActorsOfClass(GetWorld(), AEnemySpaceship::StaticClass(), FoundEnemies);
|
||||||
|
|
||||||
|
// Only spawn if we haven't reached the maximum
|
||||||
|
if (FoundEnemies.Num() < MaxEnemies)
|
||||||
|
{
|
||||||
|
|
||||||
|
UWorld* World = GetWorld();
|
||||||
|
if (!World || !EnemyClass)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Get player location
|
||||||
|
FVector PlayerLocation = GetPlayerLocation();
|
||||||
|
|
||||||
|
// Spawn enemies from multiple sides (usually 2-3 sides)
|
||||||
|
int32 NumSides = FMath::RandRange(2, 3);
|
||||||
|
float BaseAngle = FMath::RandRange(0.0f, 2.0f * PI);
|
||||||
|
|
||||||
|
for (int32 Side = 0; Side < NumSides; Side++)
|
||||||
|
{
|
||||||
|
// Calculate angle for this side
|
||||||
|
float Angle = BaseAngle + (Side * (2.0f * PI / NumSides));
|
||||||
|
FVector2D Direction(FMath::Cos(Angle), FMath::Sin(Angle));
|
||||||
|
|
||||||
|
// Spawn 1-2 enemies from this side
|
||||||
|
int32 NumEnemies = FMath::RandRange(1, 2);
|
||||||
|
|
||||||
|
for (int32 i = 0; i < NumEnemies; i++)
|
||||||
|
{
|
||||||
|
// Add some variation to the spawn position
|
||||||
|
float OffsetAngle = Angle + FMath::RandRange(-0.3f, 0.3f);
|
||||||
|
FVector2D OffsetDir(FMath::Cos(OffsetAngle), FMath::Sin(OffsetAngle));
|
||||||
|
|
||||||
|
// Increased from 2000 to MinimumSpawnDistance
|
||||||
|
FVector ProposedLocation = PlayerLocation + FVector(OffsetDir.X, OffsetDir.Y, 0) * MinimumSpawnDistance;
|
||||||
|
|
||||||
|
// Ensure the spawn location is far enough from the player
|
||||||
|
FVector SpawnLocation = EnsureMinimumSpawnDistance(ProposedLocation, PlayerLocation);
|
||||||
|
|
||||||
|
FRotator SpawnRotation = FRotator::ZeroRotator;
|
||||||
|
FActorSpawnParameters SpawnParams;
|
||||||
|
SpawnParams.SpawnCollisionHandlingOverride =
|
||||||
|
ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn;
|
||||||
|
|
||||||
|
AEnemySpaceship* NewEnemy = World->SpawnActor<AEnemySpaceship>(
|
||||||
|
EnemyClass, SpawnLocation, SpawnRotation, SpawnParams);
|
||||||
|
|
||||||
|
if (NewEnemy)
|
||||||
|
{
|
||||||
|
RotateTowardsPlayer(NewEnemy, PlayerLocation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return to random spawning
|
||||||
|
CurrentPattern = ESpawnPattern::Random;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FVector ASpaceShooterGameMode::GetScreenEdgeSpawnLocation()
|
FVector ASpaceShooterGameMode::GetScreenEdgeSpawnLocation()
|
||||||
|
|||||||
Reference in New Issue
Block a user