我正在使用Flappy Bird克隆作为练习,因为我最近开始使用XNA进行编程,而且我遇到了这个我无法理解的错误。
我在Update()函数中包含了以下代码,其中的工作是在管道离开屏幕时删除管道,以免在创建更多管道时向左无限移动:
//Pipe despawner
foreach (var pipe in pipes)
{
if (pipe.position1.X <= -180)
{
pipes.Remove(pipe);
}
}
游戏运行良好,直到第一个管道离屏,调试器暂停并通过以下消息发出信号的这部分信号:
An unhandled exception of type 'System.InvalidOperationException' occurred in mscorlib.dll
Additional information: Colección modificada; puede que no se ejecute la operación de enumeración.
对不起第二部分是西班牙语,它是我系统的语言,但希望你知道如何解决这个问题。
我相信我可以简单地不包括这部分代码,考虑到游戏的简单性,结果是无限产生的管道对性能产生的小收费,但我宁愿不采用这种做法我一开始学习游戏编程。
答案 0 :(得分:3)
问题是您在枚举集合时修改集合(通过删除管道)。这将始终在.NET中引发异常(如果您在多线程环境中执行此操作,则需要注意,因为您可以获得一些由于它而无法重现的异常)
解决问题的一种简单方法是在枚举时保留“kill”列表:
列出killList = new List();
foreach (var pipe in pipes)
{
if (pipe.position1.X <= -180)
{
killList.Add(pipe)
}
}
更容易:
IEnumerable<Pipe> killList = pipes.Where (p => p.position1.X < -100);
无论哪种方式,枚举此 new 集合,并从主要元素中删除匹配元素(从而避免错误条件):
foreach (Pipe p in killList)
pipes.Remove(p);
你完成了!再次,请注意线程。如果要在另一个线程中创建新管道,则可能很容易与此管道“发生碰撞”并导致异常。如果是这种情况,请确保在这些代码段周围加上锁。
注意,如果使用LINQ方法,实际上可以内联“killList”:
foreach (Pipe p in pipes.Where(p => p.Position1.X <= -100))
pipes.Remove(p);
正如@ rot13建议的那样,你也可以运行RemoveAll,从“Where”语句中传递谓词,如:
pipes.RemoveAll(p => p.Position1.X <= -100);
这很简单:)
答案 1 :(得分:3)
您无法从当前正在使用foreach
进行迭代的集合中删除项目。
使用for
循环并自行调整索引,或使用第二个集合来处理要删除的管道:
List<Pipe> piesToRemove = new List<Pipe>();
// First you flag every pipes you need to remove
foreach (var pipe in pipes)
{
if (pipe.position1.X <= -180)
{
pipesToRemove.Add(pipe);
}
}
//Now you remove them from your original collection
foreach (var pipe in pipesToRemove)
{
pipes.Remove(pipe);
}
答案 2 :(得分:3)
您可能只想将它们移动到屏幕的另一侧并向上/向下移动它们,而不是移除管道。
答案 3 :(得分:1)
它说你在循环时不能修改管道。尝试这样的事情:
//Pipe despawner
var unusedPipes = new List<Pipe>();
foreach (var pipe in pipes)
{
if (pipe.position1.X <= -180)
{
unusedPipes.Add(pipe);
}
}
foreach (var unusedPipe in unusedPipes)
{
pipes.Remove(unusedPipe);
}
我只是猜测管道是一个管道列表。
答案 4 :(得分:1)
其他答案完全有效,可以解决您的问题。
但是,我认为您应该知道在迭代期间不需要创建第二个集合来删除对象。
我们可以使用反向迭代从您的集合中删除对象。请尝试以下方法:
foreach (Pipe pipe in pipes.Reverse<Pipe>())
{
pipes.Remove(pipe);
}
上面的代码假设您的集合是通用List:
List<Pipe> pipes = new List<Pipe>();
修改强>
以下是我正在进行的游戏中的示例:
private List<Debris> listOfDebris = new List<Debris>();
foreach (Debris debris in listOfDebris.Reverse<Debris>())
{
CalculateDebrisLocation(debris);
// Remove debris if it travels outside level boundries
if (!debris.Rect.Intersects(currentLevel.MapRect))
listOfDebris.Remove(debris);
}