I'm making a survival game and trying to remove an object when it goes off the screen. Here is the code:
Public Sub tmrEnemyMove_Tick(sender As Object, e As EventArgs) Handles tmrEnemyMove.Tick
Dim koopaAnimation As Boolean
For Each enemy As enemy In lstEnemy
enemy.enemy.Left = enemy.enemy.Left - 20
If enemy.enemy.Tag = "koopa" Then
enemy.enemy.Image = Image.FromFile(Application.StartupPath + "\Graphics\koopa" + Trim(Str(koopaPosition)) + ".png")
If koopaAnimation = False Then
If koopaPosition = 0 Then
koopaPosition = 1
Else
koopaPosition = 0
End If
End If
koopaAnimation = True
End If
If picMario.Left < enemy.enemy.Left AndAlso enemy.enemy.Left < picMario.Right Or picMario.Left < enemy.enemy.Right AndAlso enemy.enemy.Right < picMario.Right Then
If picMario.Top < enemy.enemy.Top AndAlso enemy.enemy.Top < picMario.Bottom Or picMario.Top < enemy.enemy.Bottom AndAlso enemy.enemy.Bottom < picMario.Bottom Then
'MsgBox("Collision")
End If
End If
If enemy.enemy.Left < 0 Then
lstEnemy.Remove(enemy)
Me.Controls.Remove(enemy.enemy)
End If
Next
End Sub
The error I get is: An unhandled exception of type 'System.InvalidOperationException' occurred in mscorlib.dll Additional information: Collection was modified; enumeration operation may not execute.
If anyone could help that would be great, thanks.
The program needs access to the iterator in order to remove the current element. The for-each loop hides the iterator, so you cannot call remove . Therefore, the for-each loop is not usable for filtering.
If you want to delete elements from a list while iterating, use a while-loop so you can alter the current index and end index after each deletion.
The best way to remove items from a list while iterating over it is to use RemoveAll() .
You cannot delete an object from a collection during enumeration. You cannot modify the collection at all. That will cause an error (Collection was modified; enumeration operation may not execute). But you could add the objects that you want to delete/remove to another collection:
Dim removeEnemies = New List(Of enemy)
For Each enemy As enemy In lstEnemy
' ... '
If enemy.enemy.Left < 0 Then
removeEnemies.Add(enemy.enemy)
End If
Next
For Each enemy In removeEnemies
lstEnemy.Remove(enemy)
Me.Controls.Remove(enemy.enemy)
Next
All of the following methods will cause a list to change its version (which is checked during enumeration):
Another option is to use a For-Loop and loop it backwards:
For i As Int32 = lstEnemy.Count - 1 To 0 Step -1
Dim enemy = lstEnemy(i)
' ... '
If enemy.enemy.Left < 0 Then
lstEnemy.Remove(enemy)
Me.Controls.Remove(enemy.enemy)
End If
Next
This will not raise that error but it's not as readable. You need to go from list.Count - 1 To 0 because you want to remove items which would change the Count property and an index that was available before the item was removed causes now an ArgumentOutOfRangeException.
Last but not least, you can use List.RemoveAll:
lstEnemy.RemoveAll(Function(enemy) enemy.enemy.Left < 0)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With