[SOVLED?] Random positioning enemies do not re-spawn when all Enemies are dead for Laser Defender

I’ve recently posted this on Udemy Q&A for the course, but I figured I posted it here too.

Okay, for the life of me, I couldn’t figured this out.

Instead of having a preset number of position on my game screen. I wanted my game to randomly decide how many positions to instantiate into my Enemy Formation before instantiating my enemies. I have successfully completed this without them overlapping each other.

Unfortunately, my enemies don’t re-spawn after they all die.
It works find with preset positions, but not when I have the script randomly place them in my Enemy Formation.

The position are being instantiated as child(s) of the Enemy Formation, and my enemies are being instantiated as child(s) of the positions.

Whenever Update runs my AllMembersDead() method, it would always return false.

Eventually, I want my script to destroy all position and then recreate them before re-spawning new enemies. This way the enemies won’t always be in the same spot all the time. Which shouldn’t be hard for me to do, but first I need to get my re-spawn to work.

Oh, I’m using Unity 5.4.

Here is my code:

public GameObject enemyType;    
public float width = 10f;    
public float height = 5f;    
public float speed = 5f;    
public float spawnDelay = 0.5f;    
public GameObject positionPrefab;

private bool movingRight = true;    
private float xmax;    
private float xmin;    
private int spawnQuantity; 

// Use this for initialization  
void Start () {
    CreatePos();        
    FormationSpace();        
    SpawnEnimes();        
}

//Check If the Vector 3 Location Has Been Taken or Not
public bool IsPosAvailable(Vector3 spawnPos){
    if(Physics.CheckSphere(spawnPos, 1f)){
        return true;        
    }else {            
        return false;        
    }    
}

//Generate a New Vector3 Coordinates until it finds a unused spot on the grid
public Vector3 GetNewPos(int x){        
    Vector3 newPos = new Vector3(Random.Range(-5.28f, 5.28f), x, 0);
    
    if(!IsPosAvailable(newPos)){                   
        GetNewPos(x);            
        return newPos;        
    } else {            
        return newPos;
    }    
}

void FormationSpace(){        
    float distanceToCamera = transform.position.z - Camera.allCameras[1].transform.position.z;         
    Vector3 leftBoundary = Camera.allCameras[1].ViewportToWorldPoint(new Vector3(0, 0, distanceToCamera));       
    Vector3 rightBoundary = Camera.allCameras[1].ViewportToWorldPoint(new Vector3(1, 0, distanceToCamera));        
    xmax = rightBoundary.x;        
    xmin = leftBoundary.x;    
}

// Instantiate Positions into Enemy Formation
void CreatePos(){        
    spawnQuantity = Random.Range(5, 8);
    
    for (int x = 1; x <= 1; x++){           
        for (int i = 1; i <= spawnQuantity; i++){
            Vector3 newPos = new Vector3(Random.Range(-5.28f, 5.28f), x, 0);
            
            if (!IsPosAvailable(newPos)){                    
                               
                GameObject Pos = Instantiate(positionPrefab, newPos, Quaternion.identity) as GameObject;                   
                Pos.transform.parent = transform;                
            }  else {                    
                Vector3 newlyCreatedPos = GetNewPos(x);                    
                GameObject Pos = Instantiate(positionPrefab, newlyCreatedPos, Quaternion.identity) as GameObject;                    
                Pos.transform.parent = transform;
            } 
        }    
    }
}

void SpawnEnimes() {        
    foreach (Transform child in transform){            
        GameObject enemy = Instantiate(enemyType, child.transform.position, Quaternion.identity) as GameObject;
        enemy.transform.parent = child;
    }    
}

void SpawnUntilFull() {        
    Transform freePosition = NextFreePosition();        
    
    if (freePosition) {            
        GameObject enemy = Instantiate(enemyType, freePosition.transform.position, Quaternion.identity) as GameObject;            
        enemy.transform.parent = freePosition;        
    }             
    if (NextFreePosition()) {           
        Invoke("SpawnUntilFull", spawnDelay);        
    }    
}

public void OnDrawGizmos()    
{
    Gizmos.DrawWireCube(transform.position, new Vector3(width, height));   
}

void Update(){        
    if (movingRight) { 
        transform.position += Vector3.right * speed * Time.deltaTime;
    } else {            
        transform.position += Vector3.left * speed * Time.deltaTime;        
    }

    float rightEdgeOfFormation = transform.position.x + (0.5f * width);        
    float leftEdgeOfFormation = transform.position.x - (0.5f * width);
    
    if (leftEdgeOfFormation < xmin) {      
        movingRight = true;        
    } else if (rightEdgeOfFormation > xmax) {            
        movingRight = false;        
    }

    if (AllMembersDead()){           
        FormationSpace();            
        SpawnUntilFull();        
    }    
}
Transform NextFreePosition() {        
    foreach (Transform childPositionGameObject in transform) {            
        if(childPositionGameObject.childCount == 0){                
            return childPositionGameObject; 
         }        
    }        
        return null;    
}

bool AllMembersDead(){       
    foreach (Transform childPositionGameObject in transform){                       
        if(childPositionGameObject.childCount > 0) {                
            return false;            
        }            
    }        
        return true;    
}

As I continue to search the Net (Internet); A post on Unity Community mention about adding the instantiated References of my clone prefabs into an array.

This is what I did to my CreatePos( ) Method.

void CreatePos()
{
    GameObject Pos;
    for (int y = 1; y <= 3; y++)
    {
        spawnQuantity = Random.Range(3, 6);
        for (int i = 1; i <= spawnQuantity; i++)
        {
            Vector3 newPos = new Vector3(Random.Range(-5.28f, 5.28f), y, 0);
            if (!IsPosAvailable(newPos))
            {
                Pos = Instantiate(positionPrefab, newPos, Quaternion.identity) as GameObject;
            }
            else
            {
                Vector3 newlyCreatedPos = GetNewPos(y);
                Pos = Instantiate(positionPrefab, newlyCreatedPos, Quaternion.identity) as GameObject;
            }
            posArray[y, i] = Pos;
            Pos.transform.parent = transform;
            
        }
    }

}

Unfortunately, I’m getting a “NullReferenceException: Object reference not set to an instance of an object” error.

I’m going to keep fiddling with it till I get this to work. If anyone have any insight, please feel free to reply. Thank You!

I’ve figured out why I was getting the NullReferenceException, but I still got to figure out how to get the respawning to work.

Without using the array, I decided to added another foreach statement. Yes, my enemies do respawn now. Unfortunately, they respawn every time a enemy is destroy.

 bool AllMembersDead()
 {
        foreach (Transform childPositionGameObject in transform)
        {
            foreach (Transform grandChild in childPositionGameObject)
            {
                if (grandChild.childCount > 0)
                {
                    return false;
                }
            }
        }
        return true;
}

Notes:
childPositonGameObject.childCount always return a 1
grandChild.childCount always returns a 0

hmm…I’m going to continue to fiddle with it.
Any feedback or help would be nice. Thanks!

Hmm,
Since I was Instantiating both the Position Prefab and the Enemy Prefab, I tried just instantiating the Enemy Prefab, but they all ended up on top of each other.

I checked the Hierarchy Panel; According to it, they should be in different spots.

I was hoping someone would respond by now. Oh well!

I found a way around my situation which allows me to reach the outcome I wanted when all enemies have been destroyed.

Instead of checking if the child exist or not, I created a variable to count the number of enemies that have been instantiated.

In my EnemyBehavior script, I added a Destroy(transform.parent.gameObject); to destroy my randomly instantiated Position GameObject. This line of code is executed when an enemy is destroyed by the player.

In my EnemySpawner script, I added a if statement to check if the number of enemies is 0. If true, it will execute my createPos() method and my spawnUntilFull() Method.

if(numEnemies <= 0 ){
    createPos();
    spawnUntilFull();
}

Probably not the best solution, but it was the only solution I could come up with.
I would love any form of insight for anyone. Thank You!