4

我正在使用 C# 的 XNA 库开发一个简单的游戏。在下面的代码片段中,我得到了

收藏已修改;枚举操作可能无法执行。

第二个 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;

没有克隆列表,他们只是创建对同一列表的本地引用。直接的解决方案是将这两行更改为:

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

但这将在每次调用该方法时分配一个新列表,这对于垃圾收集(尤其是在游戏中)来说是很糟糕的,因此更好的解决方案是删除您的 foreach 循环并用反向 for 循环替换它们。这是有效的,因为只有在使用枚举器迭代集合时才会出现该异常。同样的问题不适用于常规 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;

不复制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 回答