The collection has been changed if the items are not changed.

I am developing a simple game with the XNA library for C #. In the following code snippet, I get

The collection has been modified; an enumeration operation may not be performed.

at the top of the second foreach loop. In my (relatively limited) C # experience, this happens when I try to change the base collection during a loop. However, as far as I can see, I am not modifying the enemy_positions collection in any way. All collections of this code are of type List<Vector2> .

What's going on here?

 //defines collision behaviour when enemy is hit int be_no = 0; List<Vector2> tmp_bullets = bullet_i_position; List<Vector2> tmp_enemy = enemy_positions; foreach (Vector2 bullet in bullet_i_position) { //get bullet collision box Rectangle bullet_col = new Rectangle(Convert.ToInt32(bullet.X - 12), Convert.ToInt32(bullet.Y - 12), 25, 26); int en_no = 0; foreach (Vector2 enemy in enemy_positions) { //get enemy collsion box en_box = new Rectangle(Convert.ToInt32(enemy.X), Convert.ToInt32(enemy.Y), 75, 75); if (temp_r.Intersects(en_box)) { //remove all colliding elements tmp_enemy.RemoveAt(en_no); tmp_bullets.RemoveAt(be_no); bullet_direction.RemoveAt(be_no); } en_no++; } be_no++; } //update actual lists bullet_i_position = tmp_bullets; enemy_positions = tmp_enemy; 
+4
source share
3 answers

Rows:

 List<Vector2> tmp_bullets = bullet_i_position; List<Vector2> tmp_enemy = enemy_positions; 

they don’t clone the list, they just create a local link to the same list. A direct solution would be to change these two lines to:

 List<Vector2> tmp_bullets = new List<Vector2>(bullet_i_position); List<Vector2> tmp_enemy = new List<Vector2>(enemy_positions); 

But this will assign a new list every time the method is called, which will be terrible for garbage collection (especially in the game), so the best solution is to remove your foreach loops and replace them with the opposite for the loop. This works because you only get this exception when repeating a collection using counters. The same problem does not apply to regular cycles. For instance:

 for (int i = bullet_i_position.Count - 1; i >= 0; i--) { Vector2 bullet = bullet_i_position[i]; // ... } 

Also, the reason for reverse iteration is that deleting an element at regular iteration means that you skip the element after the deleted element (because the indices will shift by 1)

+6
source
 List<Vector2> tmp_enemy = enemy_positions; 

Does not make a copy of enemy_position and assigns it to tmp_enemy. Instead, tmp_enemy points to enemy_positions. Thus, any change to tmp_enemy is reflected in enemy positions. If you want to make a real copy, this is the best approach:

 List<Vector2> tmp_enemy = new List<Vector2>(enemy_positions); 
0
source

as others noted, you are faced with the difference between reference and type values

I suggest you replace the foreach loops with something similar to below

 for(int i = 0; i<bullet_i_position.count;i++) { bool hascollided = false; for(int j = 0; j<enemy_positions.count;j++) { if(collisionOccurs) { hasCollided = true; enemy_positions.RemoveAt(j); j--; } } if(hasCollided) { bullet_i_position.RemoveAt(i); i--; } } 

you need to think about what happens if a bullet collides with two enemies at the same time in the above example, it will output both

0
source

All Articles