Mike Cuddy Mike Cuddy - 1 month ago 15
C# Question

Unity-Issue with spawning enemies after first wave is defeated

I am working on a unity project that has three different types of enemies. Right now, I have it that when the game starts one of each of the three enemies will come out. So far, so good. The issue is that when I kill one of the enemies I want the enemies from that type to spawn over and over again. So basically, game starts with one of each enemy with NO other enemies coming out. When I kill one of the types, that type comes out over and over again until they probably kill me. Here is my code:

public bool waveOne = true;
public float subTime = .5f; //Lab 11 work

#endregion Member Variables

#region Member Functions

void Start ()
{
if (waveOne == true) {
Invoke ("Spawn", spawnTime);
}
else {
// Call the Spawn function after a delay of the spawnTime and then continue to call after the same amount of time.
InvokeRepeating ("Spawn", spawnTime, spawnTime);
}
}


The above function is what spawns one of each type.

I tried creating this function to call repeating enemies:

public void callEnemies()
{
waveOne = false;
InvokeRepeating ("Spawn", spawnTime, spawnTime);

}


I would call callEnemies in my enemyHealth.cs under my death function.

public void Death ()
{
// The enemy is dead.
isDead = true;

// Turn the collider into a trigger so shots can pass through it.
capsuleCollider.isTrigger = true;
EnemyManager.Instance.callEnemies();

// Tell the animator that the enemy is dead.
anim.SetTrigger ("Dead");

// Change the audio clip of the audio source to the death clip and play it (this will stop the hurt clip playing).
enemyAudio.clip = deathClip;
enemyAudio.Play ();


#region Lab10 Addition

// Kill the Enemy (remove from EnemyList)
// Get the game object associated with "this" EneymHealth script
// Then get the InstanceID of that game object.
// That is the game object that needs to be killed.
EnemyManager.Instance.Kill(this.gameObject.GetInstanceID());

#endregion // Lab10 Addition

}


So right now, only one of my three enemies comes pouring out. But the other two do not. Any help would be great!

using System.Collections.Generic;
using UnityEngine;

public class EnemyManager : MonoBehaviour
{
#region Member Variables

#region LAB10 Addition

public static EnemyManager Instance
{
get { return EnemyManager._Instance; }
}
private static EnemyManager _Instance = null;

public EnemyManager()
{
if (EnemyManager._Instance == null) EnemyManager._Instance = this;
}

public Dictionary<int, Object> EnemyList = new Dictionary<int, Object>();

#endregion // LAB10 Addition


public PlayerHealth playerHealth; // Reference to the player's heatlh.
public GameObject enemy; // The enemy prefab to be spawned.
public float spawnTime = 3f; // How long between each spawn.
public Transform[] spawnPoints; // An array of the spawn points this enemy can spawn from.
public bool waveOne = true;
public float subTime = .5f; //Lab 11 work

#endregion Member Variables

#region Member Functions

void Start ()
{
if (waveOne == true) {
Invoke ("Spawn", spawnTime);
}
else {
// Call the Spawn function after a delay of the spawnTime and then continue to call after the same amount of time.
InvokeRepeating ("Spawn", spawnTime, spawnTime);
}
}


void Spawn ()
{
// If the player has no health left...
if(playerHealth.currentHealth <= 0f)
{
// ... exit the function.
return;
}

// Find a random index between zero and one less than the number of spawn points.
int spawnPointIndex = Random.Range (0, spawnPoints.Length);

#region LAB10 Addition

// Create an instance of the enemy prefab at the randomly selected spawn point's position and rotation.
// Original Code (next line) did not capture the resulting object.
// Instantiate(enemy, spawnPoints[spawnPointIndex].position, spawnPoints[spawnPointIndex].rotation);
Object o = Instantiate(enemy, spawnPoints[spawnPointIndex].position, spawnPoints[spawnPointIndex].rotation);
EnemyManager.Instance.EnemyList.Add(o.GetInstanceID(), o);

#endregion // LAB10 Addition

#region Lab 11

((GameObject)o).GetComponent<EnemyHealth>().EnemyHealthHandler += ScoreManager.EnemyHealthEvent;


#endregion

}

#region Lab10 Addition

public void Kill(int InstanceID)
{
if (EnemyManager.Instance.EnemyList.ContainsKey(InstanceID))
EnemyManager.Instance.EnemyList.Remove(InstanceID);

//Lab 11 notes
//bool IsAlive = (playerHealth.currentHealth <= 0f) ? true : false;

}

public void DeathToAll()
{
Dictionary<int, Object> TempEnemyList = new Dictionary<int, Object>(EnemyManager.Instance.EnemyList);
foreach (KeyValuePair<int, Object> kvp in TempEnemyList)
{
// kvp.Key; // = InstanceID
// kvp.Value; // = GameObject

GameObject go = (GameObject)kvp.Value;
go.GetComponent<EnemyHealth>().Death();
}

}

#endregion // Lab10 Addition

public void callEnemies()
{
waveOne = false;
InvokeRepeating ("Spawn", spawnTime, spawnTime);

}

#endregion Member Functions
}

Answer

If I understood your intention correctly, your pitfall is in your "Spawn" method

void Spawn ()
    {
        if(playerHealth.currentHealth <= 0f)
        {
            return;
        }
        int spawnPointIndex = Random.Range (0, spawnPoints.Length);
        Object o = Instantiate(enemy, spawnPoints[spawnPointIndex].position, spawnPoints[spawnPointIndex].rotation); // only one
        EnemyManager.Instance.EnemyList.Add(o.GetInstanceID(), o);
       ((GameObject)o).GetComponent<EnemyHealth>().EnemyHealthHandler += ScoreManager.EnemyHealthEvent;
    }

You are instantiating only one enemy off of a prefab loaded into one gameobject. We don't have enough of your code to write a complete solution, but it seems you'd want to instantiate all three and keep track of which type is killed to spawn more of that type.

EDIT: After reading your comment I recognized why it gets stuck on one enemy. Look at the singleton:

public static EnemyManager Instance
    {
        get { return EnemyManager._Instance; }
    }
    private static EnemyManager _Instance = null;

    public EnemyManager()
    {
        if (EnemyManager._Instance == null) EnemyManager._Instance = this;
    }

When you create the first enemy, the _instance is getting set to "this". When you try to make the second enemy, the if statement is false and the type of enemy remains the first one.

The static _instance is the same for all instances of the script.