Replace screen edge spawn system with simple distance-based spawning
This commit is contained in:
@@ -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,14 +182,12 @@ void ASpaceShooterGameMode::SpawnEnemyWave()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Increase wave counter and possibly switch back to random
|
|
||||||
CurrentWaveCount++;
|
CurrentWaveCount++;
|
||||||
if (CurrentWaveCount >= 3)
|
if (CurrentWaveCount >= 3)
|
||||||
{
|
{
|
||||||
CurrentPattern = ESpawnPattern::Random;
|
CurrentPattern = ESpawnPattern::Random;
|
||||||
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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user