diff --git a/Source/MyProject3/SpaceShooterGameMode.cpp b/Source/MyProject3/SpaceShooterGameMode.cpp index cf6ccdd..865c9a0 100644 --- a/Source/MyProject3/SpaceShooterGameMode.cpp +++ b/Source/MyProject3/SpaceShooterGameMode.cpp @@ -138,183 +138,41 @@ void ASpaceShooterGameMode::SpawnEnemy() void ASpaceShooterGameMode::SpawnEnemyWave() { - UWorld* World = GetWorld(); - if (!World || !EnemyClass) - return; + // Count current enemies + TArray FoundEnemies; + UGameplayStatics::GetAllActorsOfClass(GetWorld(), AEnemySpaceship::StaticClass(), FoundEnemies); - // Choose a random direction for the wave - float WaveAngle = FMath::RandRange(0.0f, 2.0f * PI); - FVector2D EdgeDirection(FMath::Cos(WaveAngle), FMath::Sin(WaveAngle)); - - // Get player location for facing direction - FVector PlayerLocation = GetPlayerLocation(); - - // Get screen bounds - TArray 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++) + // Only spawn if we haven't reached the maximum + if (FoundEnemies.Num() < MaxEnemies) { - 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 - FVector SpawnLocation = EnsureMinimumSpawnDistance(ProposedLocation, PlayerLocation); + UWorld* World = GetWorld(); + if (!World || !EnemyClass) + return; - FRotator SpawnRotation = FRotator::ZeroRotator; - FActorSpawnParameters SpawnParams; - SpawnParams.SpawnCollisionHandlingOverride = - ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn; + // Choose a random direction for the wave + float WaveAngle = FMath::RandRange(0.0f, 2.0f * PI); + FVector2D EdgeDirection(FMath::Cos(WaveAngle), FMath::Sin(WaveAngle)); - AEnemySpaceship* NewEnemy = World->SpawnActor( - EnemyClass, SpawnLocation, SpawnRotation, SpawnParams); + // Get player location for facing direction + FVector PlayerLocation = GetPlayerLocation(); - if (NewEnemy) + // Get screen bounds + TArray 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); - } - } - - // Increase wave counter and possibly switch back to random - CurrentWaveCount++; - 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 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( - 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; + 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 FVector SpawnLocation = EnsureMinimumSpawnDistance(ProposedLocation, PlayerLocation); @@ -332,10 +190,179 @@ void ASpaceShooterGameMode::SpawnEnemyFlanking() RotateTowardsPlayer(NewEnemy, PlayerLocation); } } - } - // Return to random spawning - CurrentPattern = ESpawnPattern::Random; + // Increase wave counter and possibly switch back to random + CurrentWaveCount++; + if (CurrentWaveCount >= 3) + { + CurrentPattern = ESpawnPattern::Random; + CurrentWaveCount = 0; + } + } +} + +void ASpaceShooterGameMode::SpawnEnemyFormation() +{ + // Count current enemies + TArray 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 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( + 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 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( + EnemyClass, SpawnLocation, SpawnRotation, SpawnParams); + + if (NewEnemy) + { + RotateTowardsPlayer(NewEnemy, PlayerLocation); + } + } + } + + // Return to random spawning + CurrentPattern = ESpawnPattern::Random; + } } FVector ASpaceShooterGameMode::GetScreenEdgeSpawnLocation()