There are two popular kinds of loops: for-loop and foreach-loop. Although they look similar, they are fundamentally different. A for-loop accesses the elements in an array directly, using an index, whereas a foreach-loop creates a copy of each object in the array and uses that one in the loop. However, when using classes, this is not appearent to you as a developer as classes are passed by reference and not passed by value (for more information, see What’s the difference between passing by reference vs. passing by value?, for instance), which means no actual copy of the array elements are created, but only the references to those objects are copied.
Long story short, you are not allowed to modify a collection that is currently iterated over, for instance by using a foreach-loop. A foreach-loop “pushes out” copies of every single element from your collection, one by one, so think about the inconsistencies it would create if you modified the collection while copies of elements are still being “pushed out”.
One of the easiest ways to avoid this problem is using a for-loop. In Visual Studio, if you right-click on the “foreach” keyword and look for “Quick Actions and Refactorings…”, Visual Studio should actually be able to convert the loop for you, using the option “Convert to ‘for’”:
for (int i = 0; i < GlobalVariables.enemyList.Count; i++)
{
GameObject enemy = GlobalVariables.enemyList[i];
if (Vector3.Distance(transform.position, enemy.transform.position) > 4)
{
break;
}
if (powerup)
{
GlobalVariables.enemyList.Remove(enemy);
Destroy(enemy);
}
else
{
enemy.GetComponent<Enemy>().health -= 10;
if (enemy.GetComponent<Enemy>().health <= 0)
{
GlobalVariables.enemyList.Remove(enemy);
Destroy(enemy);
}
}
}
You should not, however, remove the enemy from the list while you are still using the list in the for-loop. Instead, you could, for instance, create a local list, save all enemies that should be removed in there and remove them once you are done in the for-loop. Doing this, you could also keep your foreach-loop because you no longer modify it while in the foreach-loop.
List<GameObject> removing = new List<GameObject>(GlobalVariables.enemyList.Count);
for (int i = 0; i < GlobalVariables.enemyList.Count; i++)
{
GameObject enemy = GlobalVariables.enemyList[i];
if (Vector3.Distance(transform.position, enemy.transform.position) > 4)
{
break;
}
if (powerup)
{
removing.Add(enemy);
}
else
{
enemy.GetComponent<Enemy>().health -= 10;
if (enemy.GetComponent<Enemy>().health <= 0)
{
removing.Add(enemy);
}
}
}
for (int index = 0; index < removing.Count; index++)
{
GlobalVariables.enemyList.Remove(removing[index]);
Destroy(removing[index]);
}