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