我正在使用XNA库为C#开发一个简单的游戏。在下面的代码片段中,我得到了
第二个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;
答案 0 :(得分: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 (int i = bullet_i_position.Count - 1; i >= 0; i--)
{
Vector2 bullet = bullet_i_position[i];
// ...
}
反向迭代的原因还在于,在定期迭代时删除元素意味着您将在删除元素之后跳过元素(因为索引向下移动1)
答案 1 :(得分: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);
答案 2 :(得分: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个敌人发生碰撞会发生什么情况它会同时取消