Replace screen edge spawn system with simple distance-based spawning

This commit is contained in:
2025-04-17 08:26:48 +05:30
parent 0fed8de306
commit 322f1ac061
2 changed files with 81 additions and 236 deletions

View File

@@ -106,12 +106,11 @@ void ASpaceShooterGameMode::SpawnEnemy()
switch (CurrentPattern) switch (CurrentPattern)
{ {
case ESpawnPattern::Random: case ESpawnPattern::Random:
// Spawn a single enemy at a random edge location
{ {
UWorld* World = GetWorld(); UWorld* World = GetWorld();
if (World && EnemyClass) if (World && EnemyClass)
{ {
FVector SpawnLocation = GetScreenEdgeSpawnLocation(); FVector SpawnLocation = GetRandomSpawnLocation();
FRotator SpawnRotation = FRotator::ZeroRotator; FRotator SpawnRotation = FRotator::ZeroRotator;
FActorSpawnParameters SpawnParams; FActorSpawnParameters SpawnParams;
SpawnParams.SpawnCollisionHandlingOverride = SpawnParams.SpawnCollisionHandlingOverride =
@@ -145,44 +144,29 @@ void ASpaceShooterGameMode::SpawnEnemy()
void ASpaceShooterGameMode::SpawnEnemyWave() void ASpaceShooterGameMode::SpawnEnemyWave()
{ {
// 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(); UWorld* World = GetWorld();
if (!World || !EnemyClass) if (!World || !EnemyClass)
return; return;
// 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 // Get player location for facing direction
FVector PlayerLocation = GetPlayerLocation(); FVector PlayerLocation = GetPlayerLocation();
// Get screen bounds // Choose a random angle for the wave
TArray<FVector2D> ScreenBounds = GetScreenBounds(); float WaveAngle = FMath::RandRange(0.0f, 2.0f * PI);
float ScreenWidth = ScreenBounds[1].X - ScreenBounds[0].X; FVector2D BaseDirection(FMath::Cos(WaveAngle), FMath::Sin(WaveAngle));
// Create a line of enemies perpendicular to the direction // Create a perpendicular direction for the wave line
FVector2D PerpDirection(-EdgeDirection.Y, EdgeDirection.X); FVector2D PerpDirection(-BaseDirection.Y, BaseDirection.X);
// Spawn wave of enemies - increased distance from 2000 to MinimumSpawnDistance // Spawn wave of enemies
for (int32 i = 0; i < WaveSize; i++) for (int32 i = 0; i < WaveSize; i++)
{ {
FVector ProposedLocation; // Calculate base spawn position
ProposedLocation.X = PlayerLocation.X + (EdgeDirection.X * MinimumSpawnDistance) + FVector BaseSpawnPos = PlayerLocation + FVector(BaseDirection.X, BaseDirection.Y, 0) * 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 // Offset along the wave line
FVector SpawnLocation = EnsureMinimumSpawnDistance(ProposedLocation, PlayerLocation); FVector Offset = FVector(PerpDirection.X, PerpDirection.Y, 0) * (i - WaveSize / 2) * FormationSpacing;
FVector SpawnLocation = BaseSpawnPos + Offset;
FRotator SpawnRotation = FRotator::ZeroRotator; FRotator SpawnRotation = FRotator::ZeroRotator;
FActorSpawnParameters SpawnParams; FActorSpawnParameters SpawnParams;
@@ -198,7 +182,6 @@ void ASpaceShooterGameMode::SpawnEnemyWave()
} }
} }
// Increase wave counter and possibly switch back to random
CurrentWaveCount++; CurrentWaveCount++;
if (CurrentWaveCount >= 3) if (CurrentWaveCount >= 3)
{ {
@@ -206,7 +189,6 @@ void ASpaceShooterGameMode::SpawnEnemyWave()
CurrentWaveCount = 0; CurrentWaveCount = 0;
} }
} }
}
void ASpaceShooterGameMode::SpawnEnemyFormation() void ASpaceShooterGameMode::SpawnEnemyFormation()
{ {
@@ -312,22 +294,13 @@ void ASpaceShooterGameMode::SpawnEnemyFormation()
void ASpaceShooterGameMode::SpawnEnemyFlanking() 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(); UWorld* World = GetWorld();
if (!World || !EnemyClass) if (!World || !EnemyClass)
return; return;
// Get player location
FVector PlayerLocation = GetPlayerLocation(); FVector PlayerLocation = GetPlayerLocation();
// Spawn enemies from multiple sides (usually 2-3 sides) // Spawn enemies from multiple sides (2-3 sides)
int32 NumSides = FMath::RandRange(2, 3); int32 NumSides = FMath::RandRange(2, 3);
float BaseAngle = FMath::RandRange(0.0f, 2.0f * PI); float BaseAngle = FMath::RandRange(0.0f, 2.0f * PI);
@@ -335,7 +308,6 @@ void ASpaceShooterGameMode::SpawnEnemyFlanking()
{ {
// Calculate angle for this side // Calculate angle for this side
float Angle = BaseAngle + (Side * (2.0f * PI / NumSides)); float Angle = BaseAngle + (Side * (2.0f * PI / NumSides));
FVector2D Direction(FMath::Cos(Angle), FMath::Sin(Angle));
// Spawn 1-2 enemies from this side // Spawn 1-2 enemies from this side
int32 NumEnemies = FMath::RandRange(1, 2); int32 NumEnemies = FMath::RandRange(1, 2);
@@ -344,13 +316,10 @@ void ASpaceShooterGameMode::SpawnEnemyFlanking()
{ {
// Add some variation to the spawn position // Add some variation to the spawn position
float OffsetAngle = Angle + FMath::RandRange(-0.3f, 0.3f); float OffsetAngle = Angle + FMath::RandRange(-0.3f, 0.3f);
FVector2D OffsetDir(FMath::Cos(OffsetAngle), FMath::Sin(OffsetAngle)); FVector Direction(FMath::Cos(OffsetAngle), FMath::Sin(OffsetAngle), 0.0f);
// Increased from 2000 to MinimumSpawnDistance // Calculate spawn position
FVector ProposedLocation = PlayerLocation + FVector(OffsetDir.X, OffsetDir.Y, 0) * MinimumSpawnDistance; FVector SpawnLocation = PlayerLocation + (Direction * (MinimumSpawnDistance + FMath::RandRange(0.0f, 300.0f)));
// Ensure the spawn location is far enough from the player
FVector SpawnLocation = EnsureMinimumSpawnDistance(ProposedLocation, PlayerLocation);
FRotator SpawnRotation = FRotator::ZeroRotator; FRotator SpawnRotation = FRotator::ZeroRotator;
FActorSpawnParameters SpawnParams; FActorSpawnParameters SpawnParams;
@@ -367,108 +336,28 @@ void ASpaceShooterGameMode::SpawnEnemyFlanking()
} }
} }
// Return to random spawning
CurrentPattern = ESpawnPattern::Random; CurrentPattern = ESpawnPattern::Random;
} }
}
FVector ASpaceShooterGameMode::GetScreenEdgeSpawnLocation() FVector ASpaceShooterGameMode::GetRandomSpawnLocation()
{ {
FVector PlayerLocation = GetPlayerLocation(); FVector PlayerLocation = GetPlayerLocation();
TArray<FVector2D> ScreenBounds = GetScreenBounds();
// Decide which edge to spawn from (0 = top, 1 = right, 2 = bottom, 3 = left) // Generate a random angle in radians
int32 Edge = FMath::RandRange(0, 3);
FVector SpawnLocation;
float RandomPos;
// Increased margin to spawn farther from screen edges
float ExtendedMargin = ScreenSpawnMargin + 500.0f;
switch (Edge)
{
case 0: // Top edge
RandomPos = FMath::RandRange(ScreenBounds[0].X, ScreenBounds[1].X);
SpawnLocation = FVector(RandomPos, ScreenBounds[0].Y - ExtendedMargin, PlayerLocation.Z);
break;
case 1: // Right edge
RandomPos = FMath::RandRange(ScreenBounds[0].Y, ScreenBounds[1].Y);
SpawnLocation = FVector(ScreenBounds[1].X + ExtendedMargin, RandomPos, PlayerLocation.Z);
break;
case 2: // Bottom edge
RandomPos = FMath::RandRange(ScreenBounds[0].X, ScreenBounds[1].X);
SpawnLocation = FVector(RandomPos, ScreenBounds[1].Y + ExtendedMargin, PlayerLocation.Z);
break;
case 3: // Left edge
RandomPos = FMath::RandRange(ScreenBounds[0].Y, ScreenBounds[1].Y);
SpawnLocation = FVector(ScreenBounds[0].X - ExtendedMargin, RandomPos, PlayerLocation.Z);
break;
}
// Ensure the spawn location is far enough from the player
return EnsureMinimumSpawnDistance(SpawnLocation, PlayerLocation);
}
FVector ASpaceShooterGameMode::GetSpawnZoneLocation()
{
// If no spawn zones are defined, return a screen edge location
if (SpawnZones.Num() == 0)
{
return GetScreenEdgeSpawnLocation();
}
// Filter active spawn zones
TArray<FSpawnZone> ActiveZones;
float TotalWeight = 0.0f;
for (const FSpawnZone& Zone : SpawnZones)
{
if (Zone.bActive)
{
ActiveZones.Add(Zone);
TotalWeight += Zone.SpawnWeight;
}
}
// If no active zones, return screen edge
if (ActiveZones.Num() == 0)
{
return GetScreenEdgeSpawnLocation();
}
// Select a zone based on weight
float RandomWeight = FMath::RandRange(0.0f, TotalWeight);
float WeightSum = 0.0f;
FVector PlayerLocation = GetPlayerLocation();
for (const FSpawnZone& Zone : ActiveZones)
{
WeightSum += Zone.SpawnWeight;
if (RandomWeight <= WeightSum)
{
// Generate random point within this zone's radius
float RandomAngle = FMath::RandRange(0.0f, 2.0f * PI); float RandomAngle = FMath::RandRange(0.0f, 2.0f * PI);
float RandomRadius = FMath::RandRange(0.0f, Zone.Radius);
FVector SpawnOffset( // Create a direction vector from the random angle
FMath::Cos(RandomAngle) * RandomRadius, FVector Direction(
FMath::Sin(RandomAngle) * RandomRadius, FMath::Cos(RandomAngle),
FMath::Sin(RandomAngle),
0.0f 0.0f
); );
FVector ProposedLocation = Zone.Location + SpawnOffset; // Use the minimum spawn distance plus some random additional distance
float SpawnDistance = MinimumSpawnDistance + FMath::RandRange(0.0f, 500.0f);
// Ensure the spawn location is far enough from the player // Calculate the spawn position
return EnsureMinimumSpawnDistance(ProposedLocation, PlayerLocation); return PlayerLocation + (Direction * SpawnDistance);
}
}
// Fallback
return GetScreenEdgeSpawnLocation();
} }
void ASpaceShooterGameMode::UpdateDifficulty() void ASpaceShooterGameMode::UpdateDifficulty()
@@ -499,48 +388,6 @@ FVector ASpaceShooterGameMode::GetPlayerLocation()
return FVector::ZeroVector; return FVector::ZeroVector;
} }
TArray<FVector2D> ASpaceShooterGameMode::GetScreenBounds()
{
TArray<FVector2D> Bounds;
FVector2D ScreenMin, ScreenMax;
// Get player controller for screen info
APlayerController* PlayerController = UGameplayStatics::GetPlayerController(GetWorld(), 0);
if (!PlayerController)
{
// Fallback values if no controller
Bounds.Add(FVector2D(-2000, -2000));
Bounds.Add(FVector2D(2000, 2000));
return Bounds;
}
// Get viewport size
int32 ViewportSizeX, ViewportSizeY;
PlayerController->GetViewportSize(ViewportSizeX, ViewportSizeY);
// Get world location of screen corners
FVector WorldLocation, WorldDirection;
// Top-Left corner
PlayerController->DeprojectScreenPositionToWorld(0, 0, WorldLocation, WorldDirection);
ScreenMin = FVector2D(WorldLocation.X, WorldLocation.Y);
// Bottom-Right corner
PlayerController->DeprojectScreenPositionToWorld(ViewportSizeX, ViewportSizeY, WorldLocation, WorldDirection);
ScreenMax = FVector2D(WorldLocation.X, WorldLocation.Y);
// Add some margin
ScreenMin.X -= 200;
ScreenMin.Y -= 200;
ScreenMax.X += 200;
ScreenMax.Y += 200;
Bounds.Add(ScreenMin);
Bounds.Add(ScreenMax);
return Bounds;
}
void ASpaceShooterGameMode::RotateTowardsPlayer(AEnemySpaceship* Enemy, const FVector& PlayerLocation) void ASpaceShooterGameMode::RotateTowardsPlayer(AEnemySpaceship* Enemy, const FVector& PlayerLocation)
{ {
if (!Enemy) if (!Enemy)

View File

@@ -109,11 +109,9 @@ private:
void SpawnEnemyWave(); void SpawnEnemyWave();
void SpawnEnemyFormation(); void SpawnEnemyFormation();
void SpawnEnemyFlanking(); void SpawnEnemyFlanking();
FVector GetScreenEdgeSpawnLocation(); FVector GetRandomSpawnLocation();
FVector GetSpawnZoneLocation();
void UpdateDifficulty(); void UpdateDifficulty();
FVector GetPlayerLocation(); FVector GetPlayerLocation();
TArray<FVector2D> GetScreenBounds();
void RotateTowardsPlayer(AEnemySpaceship* Enemy, const FVector& PlayerLocation); void RotateTowardsPlayer(AEnemySpaceship* Enemy, const FVector& PlayerLocation);
// New helper method to ensure minimum spawn distance // New helper method to ensure minimum spawn distance