Enemy Spawn Script Spawning Infinite Enemies [Help]

I’m trying to test my enemy spawn script (c#), and I thought I had it pretty well figured out. For the meantime it’s all attached to my enemy prefab, but eventually I will attach it to the player. This is how the script is supposed to work:

  1. In the start function, check how many objects have the tag “Enemy”.
  2. If it’s greater than 0 (for testing) run the StartLevel function, passing a levelIndex variable.
  3. In StartLevel, do some things (not implemented), then call SpawnEnemy, passing the number of enemies to spawn.
  4. In SpawnEnemy, for each enemy that needs to be spawned, find a random point around the player (x,z), then pass that point to a function that finds the terrain height at this point. If it returns a valid number, and passes some other conditions (isn’t too close to player, or too close to other spawned enemies) spawn this enemy, facing the player.
  5. Save this spawn point as the lastSpawnPoint for any other enemies that need spawning.

Here is the relevant code:

 using UnityEngine;
    using System.Collections;
    
    public class EnemyScript : MonoBehaviour {
    
    	public Transform playerPos;
    	public float enemySpeed = 5f;
    	public float detectionRadius = 150;
    	public CharacterController cc;
    	public GameObject enemyPrefab;
    	public bool sawPlayer = false;
    	public Vector3 playerDirection = Vector3.zero;
    	public float verticalSpeed;
    	public float spawnDistance = 50.0f;
    	public float minEnemySpawnDensity = 6f;
    	public float minSpawnDistance = 20f;
    	public int spawnThisMany = 0;
    
    
    	// Use this for initialization
    	void Start () {

                //get the transform of the player
    		playerPos = GameObject.FindWithTag("Player").transform;

                //get the character controller attached to the enemyPrefab
    		cc.GetComponent<CharacterController>();

                //if there are no enemies present, start level 1
    		if(GameObject.FindGameObjectsWithTag("Enemy").Length >= 0){
    			StartLevel(spawnThisMany);
    		}
    
    	}
    
    	//this function handles the spawning of enemies around you. It is called
    	//from the startLevel function, which handles the number of enemies in 
    	//each level.
    	void SpawnEnemy(int numberOfEnemies){

                //find a random point around the player
    		Vector3 spawnPoint = Random.insideUnitCircle.normalized*spawnDistance;
    		Vector3 lastSpawnPoint = Vector3.zero;

                //this sets the spawn point height to the terrain height, plus a the radius of the sphere's character controller
    		spawnPoint.y = TerrainHeight(spawnPoint) + cc.radius;

                for(int enemyCount = 0; enemyCount < numberOfEnemies; enemyCount++){

                        //if terrain height returns infinity, or the difference in this spawn
    			//point and the last spawn point is greater than the minimus spawn
    			//density, or the enemy spawns to close to the player, start over.
    			if(spawnPoint.y == Mathf.Infinity || (spawnPoint - lastSpawnPoint).magnitude <= minEnemySpawnDensity || (spawnPoint - playerPos.position).magnitude <= minSpawnDistance){
    				SpawnEnemy(numberOfEnemies - enemyCount);
    			}

                        //if all the conditions are met, an enemy is spawned facing the player,
    			//and the spawn point is saved as the last spawn point.
    			else{
    				//setting look direction for enemy, cancelling out the y portion
    				Vector3 lookDirection = playerPos.position;
    				lookDirection.y = 0f;
    				Instantiate(enemyPrefab,spawnPoint,Quaternion.LookRotation(lookDirection));
    				lastSpawnPoint = spawnPoint;
    			}
    		}
    
    	}

        //this starts each level
    	void StartLevel(int levelIndex){
                //do stuff here
    		SpawnEnemy (levelIndex);
    	}

    	//TerrainHeight finds the height of the terrain given a 2D position vector
    	float TerrainHeight(Vector2 spawnPoint){

    		//declare a raycast hitpoint
    		RaycastHit hitPoint;

    		//go to spawnPoint and cast a ray upwards, if it hits return that y position.
    		//if it doesn't, shoot a ray downwards and it should hit, if not, return infinity.
    		if(Physics.Raycast(spawnPoint,Vector3.up, out hitPoint)){
    			return hitPoint.transform.position.y;
    		}
    		else if(Physics.Raycast(spawnPoint,Vector3.down, out hitPoint)){
    			return hitPoint.transform.position.y;
    		}
    		else{
    			return Mathf.Infinity;
    		}
    	}
    }

I’m pretty sure the problem lies within my for statement, although for the life of me I can’t figure it out. It’s probably something silly. But everytime I go to play mode, the enemies just keep piling up and lagging my game. About 150 spawn before I can get out of play mode. Thanks for any help.

It looks like you accidentally set up a recursive method in SpawnEnemy. You pass in the number to spawn and use that in your for loop, but then call SpawnEnemy with the same number within the for loop. This will just keep going forever.
Rather than having your for loop inside SpawnEnemy, have it outside, and have the methods only spawn one at a time.

@Moohasha is correct in that every time you call recursively call SpawnEnemy you are going to double up on the remainder of your enemy spawns. The reason you will double up is that you are starting a new loop, and will (once it is finished) continue the old loop.

I would recommend an iterative rather than recursive approach:

    void SpawnEnemy(int numberOfEnemies) {
        Vector3 lastSpawnPoint = Vector3.zero;
        Vector3 spawnPoint = Vector3.zero;
        for(int enemyCount = 0; enemyCount < numberOfEnemies; enemyCount++){
            do {
                spawnPoint = Random.insideUnitCircle.normalized * spawnDistance;
                spawnPoint.y = TerrainHeight(spawnPoint) + cc.radius;
            } while(IsInvalidSpawnPoint(spawnPoint, lastSpawnPoint));
            
            Vector3 lookDirection = playerPos.position;
            lookDirection.y = 0f;
            Instantiate(enemyPrefab, spawnPoint, Quaternion.LookRotation(lookDirection));
            lastSpawnPoint = spawnPoint;
        }
    }

    boolean IsInvalidSpawnPoint(Vector3 spawnPoint,Vector3 lastSpawnPoint){
        return spawnPoint.y == Mathf.Infinity ||
               (spawnPoint - lastSpawnPoint).magnitude <= minEnemySpawnDensity ||
               (spawnPoint - playerPos.position).magnitude <= minSpawnDistance;
    }