Removing dead enemies from an iterating list

So I have a series of enemies in a list, constantly in a coroutine and told when to attack by a foreach loop. When an enemy dies, he notifies the class containing the list to remove it. Since I can’t remove it directly since the list is under an iteration, I tried instead to put the dead enemies in a Dead Enemy list and remove them from the main list after the foreachloop. However, how would I remove a series of GameObjects in a list(Dead Enemy) from another list (main list)? I tried a foreach loop that removes each dead enemy from the mainlist, but that ends up freezing the editor.

for (int n = 0; n < enemy.Count) {
   if (enemy[n].isDead) {
      enemy.RemoveAt(n);
      n--;
   }
}
1 Like

Can you explain why n is decreasing, or why n starts at 0?

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class TurnManager : MonoBehaviour
{
    public GameObject currentarena;
    public GameObject enemyAttacking;
    public List<GameObject> enemylist = new List<GameObject>();
    public List<GameObject> enemiesdefeated = new List<GameObject>();
    GameObject[] currentenemies;
    GameObject player;
    public int direction;

    void Awake()
    {

    }
    public void SpawnDone()
    {

    }

    public void StartCombat()
    {
        player = GameObject.FindGameObjectWithTag("Player");
        EnemyCount();
        //StartCoroutine(EnemyTurn());
    }
    void Update()
    {

    }
    void EnemyCount()
    {
        enemylist.Clear();
        currentenemies = GameObject.FindGameObjectsWithTag("enemy");
        Debug.Log("EnemyCount");
        if (currentenemies.Length > 0)
        {
            foreach (GameObject character in currentenemies)
            {
                enemylist.Add(character);
                enemylist.Sort(delegate (GameObject a, GameObject b)
                {
                    return (a.GetComponent<EnemyVariables>().speed).CompareTo(b.GetComponent<EnemyVariables>().speed);
                });
            }
        }
        else if(currentenemies.Length == 0)
        {
            EndCombat();
            Debug.Log("End Combat");
        }
        StartCoroutine(EnemyTurn());
    }
    public void EnemyDeath(GameObject enemy, int dir)
    {
       //enemylist.Remove(enemy);
       //enemiesdefeated.Add(enemy);
        direction = dir;

    }
    IEnumerator EnemyTurn()
    {
        foreach (GameObject enemy in enemylist)
        {
            enemyAttacking = enemy;
            Debug.Log("EnemyTurn");
            EnemyScript attackscript = enemy.GetComponent<EnemyScript>();
            attackscript.TurnChosen();
            while (attackscript.attacking)
            {

                yield return null;

            }
        }
        for (int n = enemylist.Count - 1; n >= 0; n--)
        {
            if (enemylist[n].tag == "dead")
            {
                enemylist.RemoveAt(n);
              
            }
        }
        Debug.Log("EnemyTurn Finish");
            EnemyCount();
       
            //StartCoroutine(EnemyTurn());
        }

    public void EndCombat()
    {
        //player.SendMessage("EndCombat()");
        player.GetComponent<PlayerCombatScript>().EndCombat();
        enemylist.Clear();
        currentarena.GetComponent<BattlegroundData>().ChangeArena(direction);
        Debug.Log("EnemyManager Exit");
    }
}

this is the code of the turn manager with the enemylist. the foreach and for loop combo seems to be responsible for freezing the editor

why not just have the “enemy” remove itself from the list when it’s set to dead rather than trying to do them all together in some “control” loop.

also, in passing, lines 41-48, you are sorting every time you add something… wouldn’t it be alot more efficient to add everything and sort the list at the end. Nothing in that code is dependent on the order.

Removing elements from the list as you itterate backwards is a common way to remove items. That way your iteration doesn’t get mixed up.

The code sample is invalid, but it should read something like this.

for (int n = enemy.Count - 1; n >= 0; n--) {
   if (enemy[n].isDead) {
      enemy.RemoveAt(n);
   }
}
4 Likes

@Kiwasi I also saw a bunch of people just simply iterate from 0 and just removing 1,when they remove something from the list. I used this technique quite a lot. My code sample was invalid, yes, I forgot the n++ from the end.

@DeathByRhino You should learn a bit of c# before jumping into unity, because I think you don’t understand the basic loops