# Method for spawning enemies according to player score and game time

I'm making a top-down shooter and want to scale the difficulty of the game according to what the score is and how much time has Passed. Along with this, I want to spawn enemies in different patterns and increase the intervals at which these enemies are shown. I'm going for a similar effect to Geometry wars. However, I can think of a to do this other than have multiple if-else statments, e.g. :

        if (score > 1000) {
//spawn x amount if enemies
}
else if (score > 10000) {
//spawn x amount of enemy type 1 & 2
}
else if (score > 15000) {
//spawn x amount of enemy type 1 & 2 & 3
}
else if (score > 25000) {
//spawn x amount of enemy type 1 & 2 & 3
//create patterns with enemies
}
...etc


What would be a better method of spawning enemies as I have described?

• Couldn't you use a random generator? "If random(0.0 - 1.0 result) < (score / factor)(0.0 - 1.0 result) Then generate MOB". Set your factor accordingly
– Paul
Sep 11, 2012 at 20:14

Here are some ideas that come to my mind:

• Calculate the score per minute ratio. For example, weaker enemies give 25 points, stronger ones 100 and the badasses, let's say 250. Use that value (score/min) to adjust the number of enemies that spawn. For example, determine the average score/min of a casual player and use something like numEnemies = currentSPM/averageSPM * 100. Adjustments are needed if player simply avoids enemies -> numEnemies approaches 0 and he wins the game easily. You can control WHEN there will be a change in the number of enemies - for example if currentSPM / averageSPM >= 0.5 (that way the game will not drop the number of enemies being generated below 50%).
• Calculate aforementioned spm for each type of enemy. For example, if the player is successfully killing the weaker enemies but avoiding the stronger ones, increase the number of stronger ones also: e1_numEnemies = e1_curSPM/e1_avgSPM*100; e2_numEnemies = (e2_curSPM/e2_avgSPM + e1_curSPM/e1_curSPM*0.25)*50 (...) this adds more type 2 (stronger) enemies the more player kills type 1 enemies (the weaker ones) - but the SPM ratio for e1 contributes with just 25% to the number of type 2 enemies.
• Divide the play area into quadrants. Let's say it's a 4 x 8 field (it's a top down shooter, right?). Detect in which quadrants the enemies are most likely to die and make new enemies come at player from that ones more likely.
• Alternatively, determine in which part of the playfield the player's ship is the most. Also make enemies spawn there more often (if they're at the left corner of the screen for example most of the time, that means the other parts of the screen are to hostile, and that one is not, so you want to make it more hostile).
• Detect which weapon the player uses most successfully and make the enemies a little more resistant to that type of weapon.

For endless games like Geometry Wars your approach is a bit too static. I would calculate the wanted difficulty from multiple factors, then randomize it. With the following example harder enemies would get more probable while weaker enemies get less probable the more advanced you are into the game. Using random numbers increases the dynamics of your game, however can create "unfair" situations. Which is more important depends on your target audience.

bool spawnEnemies(float spawnLevel)
{
// After 2 minutes, only spawn patterns of the smaller enemies anymore
if(getTime() > 120.f)
if(spawnLevel < 2000)
spawnLevel = 2000;
// Spawn a small amount of weak enemies
if(spawnLevel < 500)
[...]
// Spawn single normal enemies
else if(spawnLevel < 1000)
[...]
// Spawn patterns of weak or normal enemies
else if(spawnLevel < 2000)
{
float temp=randomFloat(1.f);
if(temp < 0.2f)
[... spawn pattern 1 ...]
else if(temp < 0.4f)
[... spawn pattern 2 ...]
else
[... spawn pattern 3 ...]
}
// Harder enemy
else if(spawnLevel < 20000)
[...]
// Bosslike enemy
else if(spawnLevel < 200000)
[...]
[...]
}
[...]
float timeFactor=difficultyLevel*5.f;
float scoreFactor=1.f/difficultyLevel;
float spawnLevel=getTime()*timeFactor+getScore()*scoreFactor;
if([...]) spawnEnemies(randomFloat(spawnLevel));
[...]


One route I might take is to implement some sort of level class and level manager that allows me to determine when a level has been beaten and to move onto the next one when it has. The following is a rather crude example and should be implemented in a way to fit whatever engine design you are working towards:

//LevelManager levelManager = new LevelManager(); //Queue up your levels wherever you instantiate the LevelManager maybe

//If the level has been beaten
//Could be a score check, game time check, boss beaten check, etc.
if (!LevelManager.ActiveLevel.IsActive)
{
//Queue up next level
LevelManager.NextLevel();
}