我昨天发布了关于游戏中两个实例,敌人和子弹之间碰撞的求助信息。
解决方案是:
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子弹)行。
老实说,我不知道应该从哪里开始,所以感谢任何帮助。
答案 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);
}