4

私はC#用のXNAライブラリを使用して簡単なゲームを開発しています。次のコードスニペットでは、

コレクションが変更されました。列挙操作が実行されない場合があります。

2番目のforeachループの先頭でエラーが発生しました。私の(比較的限られた)C#の経験では、これはループ中に基になるコレクションを変更しようとしたときに発生します。ただし、私が見る限り、enemy_positionsコレクションを変更しているわけではありません。このコードのすべてのコレクションは、タイプがList<Vector2>です。

ここで何が起きてるの?

//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

3 に答える 3

6

台詞:

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

リストのクローンを作成しているのではなく、同じリストへのローカル参照を作成しているだけです。直接的な解決策は、これら2つの行を次のように変更することです。

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

ただし、これにより、メソッドが呼び出されるたびに新しいリストが割り当てられます。これは、ガベージコレクション(特にゲーム)ではひどいものになるため、foreachループを削除し、reverseforループに置き換えることをお勧めします。これが機能するのは、列挙子を使用してコレクションを反復処理するときにのみ例外が発生するためです。同じ問題は通常のforループには当てはまりません。例えば:

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

    // ...
}

また、逆反復の理由は、定期的に反復しながら要素を削除すると、削除された要素の後に要素をスキップすることを意味するためです(インデックスが1つ下にシフトするため)

于 2012-12-31T12:25:56.160 に答える
0
List<Vector2> tmp_enemy = enemy_positions;

敵の位置のコピーを作成して、それをtmp_enemyに割り当てません。代わりに、tmp_enemyはenemy_positionsを指します。したがって、tmp_enemyの変更は、enemy_positionsに反映されます。実際のコピーを作成する場合は、これがより適切なアプローチです。

List<Vector2> tmp_enemy = new List<Vector2>(enemy_positions);
于 2012-12-31T12:28:26.090 に答える
0

他の人が述べているように、参照型と値型の違いに遭遇しました

foreachループを以下のようなものに置き換えることをお勧めします

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--;
      }
}

上記の例で弾丸が2人の敵に同時に衝突した場合、両方を取り除くとどうなるかを考慮する必要があります。

于 2012-12-31T13:02:16.127 に答える