2013-05-24 8 views
6

私はサバイバルゲームを作っていて、オブジェクトが画面外に出たときにオブジェクトを削除しようとしています。ここでは、コードは次のようになります。各ループのオブジェクトを削除する

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 

私が手にエラーがある:「System.InvalidOperationException」種類の 未処理の例外がmscorlib.dllが で発生しました追加情報:コレクションが変更されました。列挙操作が実行されないことがあります。

誰でも助けてくれれば幸いです。

+2

をあなたがそれについて考えるならば、明白な理由があります。ループ中にオブジェクトへの参照を取得し、その後に削除する – DavidB

答えて

1

.NETは、コンテンツを列挙しているときにコレクションを変更したときに、実際にそれが気に入らない場合があります。このようなコレクションから要素を削除する予定がある場合は、foreachループをforループに貼り付けてみてください。

13

列挙中にコレクションからオブジェクトを削除することはできません。コレクションはまったく変更できません。これによりエラーが発生します(コレクションが変更されました。列挙操作ではが実行されません)。しかし、あなたが削除したいオブジェクトを追加することができます/別のコレクションに削除:

  • を追加します。

    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 
    

    これらのメソッドは、リストはそれを変更するようになりますが(列挙中にチェックされている)バージョンです

  • クリア
  • 挿入
  • InsertRange
  • を削除します
  • RemoveRange
  • RemoveAt
  • リバース
  • [インデクサセッター]
  • ソート

別のオプションは、後方For-Loopやループ、それを使用することです:

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 

この意志そのエラーは発生しませんが、それは読みにくいです。 から0に移動する必要があります。これは、Countプロパティと、アイテムが削除される前に利用可能だったインデックスを変更するアイテムを削除して、今度はArgumentOutOfRangeExceptionになります。

なく、少なくとも最後に、あなたはList.RemoveAllを使用することができます。

エンティティフレームワーク(ElementAt(i))を使用して
lstEnemy.RemoveAll(Function(enemy) enemy.enemy.Left < 0) 
+1

+1すてきな答え –

+0

他のオプションはしばらく使用することです。素晴らしい答え –

0

一つの例:それをループしながら、あなたはこのようなコレクションを変更canot

for (int i = 0; i < db.Itens.Count(); i++) 
{ 
    Item item = db.Itens.ElementAt(i); 
    if (item.Id == 0) // put a condition 
    { 
     db.Itens.Remove(item); 
     i--; 
    } 
} 
関連する問題