由于碰撞而导致removeAt()出现问题

时间:2014-11-02 23:37:14

标签: c# xamarin monogame

我昨天发布了关于游戏中两个实例,敌人和子弹之间碰撞的求助信息。

解决方案是:

foreach (Enemy enemy in enemies)
    foreach (Bullet bullet in bullets)
        if (bullet.boundingBox.Intersects(enemy.boundingBox)) 
        { 
            score += 1;
        }

当然,这对得分很明智,因为每当子弹与敌人相交时,我现在获得一分。当我需要销毁两个对象(不是所有对象,只是已经交叉的对象)时,会出现问题。我的第一个想法是使用removeAt()函数,如下所示:

if (bullet.boundingBox.Intersects(enemy.boundingBox)) 
    { 
        score += 1;
        removeAt();
    }    

但当然这不起作用,因为它通常用于索引,例如" removeAt(i)"。然后我试着把我引用的整个代码块放在顶部,并将它放在两个列表中,如下所示:

for (int i = bullets.Count - 1; i >= 0; i--)
{
    bullets[i].Update(delta);   

    //Bullets being destroyed upon leaving 
    if (bullets[i].position.Y < 0)
            bullets.RemoveAt(i);

    foreach (Enemy enemy in enemies)
        foreach (Bullet bullet in bullets)
            if (bullet.boundingBox.Intersects(enemy.boundingBox)) 
            { 
                bullets.RemoveAt(i);
            }
}

游戏将在此时运行,但一旦子弹与敌人发生碰撞就会崩溃。错误&#34; System.InvalidOperationException&#34;被扔在&#34; foreach(子弹中的Bullet子弹)行。

老实说,我不知道应该从哪里开始,所以感谢任何帮助。

2 个答案:

答案 0 :(得分:3)

之所以这样,是因为您在枚举时会从bullets中删除元素。见:

for (int i = bullets.Count - 1; i >= 0; i--)

您将子弹的数量存储在i中,并且每次都减少它。然后,您的代码中有两个位置,其中逻辑删除项目符号,从而更改bullets的计数。你永远不应该修改你要枚举的数组。

关于一个可能的解决方案,你可以完成Jason在评论中指出的内容。向您的类添加bool Delete属性,然后将RemoveAt标志设置为true,而不是调用Delete。代码如下所示:

for (int i = bullets.Count - 1; i >= 0; i--)
{
    bullets[i].Update(delta);   

    //Bullets being destroyed upon leaving 
    if (bullets[i].position.Y < 0)
    {
        bullets[i].Delete = true;
    }

    foreach (Enemy enemy in enemies)
    {
        if (bullets[i].boundingBox.Intersects(enemy.boundingBox)) 
        { 
            bullets[i].Delete = true;
        }
    }
}

bullets.RemoveAll(b => b.Delete);

希望这有所帮助,祝你好运!

答案 1 :(得分:0)

通常,我更喜欢为要删除的对象维护一个新集合,然后在处理完成后删除它们。我发现它很容易理解并且没有可疑的控件属性添加。与此类似....

List<Bullet> expiredBullets = new List<Bullet>();

for (int i = bullets.Count - 1; i >= 0; i--)
{
  bullets[i].Update(delta);

  if (bullets[i].position.Y < 0)
  {
    expiredBullets.Add(bullets[i]);
  }
}

foreach(Bullet expiredBullet in expiredBullets)
{
  bullets.Remove(expiredBullet);
}