我正在使用for循环或foreach循环(无关紧要)来遍历所有需要更新或绘制的对象。但是,当某个对象被杀死时,我希望它再次从集合中删除。
为此,我将对象添加到一个死对象列表中,然后,在绘制并更新了所有内容之后,我将遍历此列表中的所有内容,并将列表中的对象也从原始源中删除。
有更好的方法吗?
我正在使用for循环或foreach循环(无关紧要)来遍历所有需要更新或绘制的对象。但是,当某个对象被杀死时,我希望它再次从集合中删除。
为此,我将对象添加到一个死对象列表中,然后,在绘制并更新了所有内容之后,我将遍历此列表中的所有内容,并将列表中的对象也从原始源中删除。
有更好的方法吗?
Answers:
首先:术语。如果您说“垃圾清单”,人们会认为您在谈论垃圾收集器。我们称其为“死名单”。
正如您可能已经发现的,因此是您的问题,在迭代集合时,您无法从集合中删除项目。如果您的收藏集是一种List<>
最简单的删除项目的方法是:
for(int i = list.Count-1; i >= 0; --i)
{
if(list[i].IsDead)
list.RemoveAt(i);
}
请注意,您向后迭代。您可以在向前迭代时删除项目,但这比较麻烦,并且需要goto
。您无法使用来做到这一点foreach
。
您可以与更新循环分开进行删除。或者,您可以将其合并到更新循环中。始终RemoveAt
在循环结束时执行-在循环中的该点之后,list[i]
不能视为有效(它在下一次迭代中再次变为有效)。
还要注意,每个对象都有自己的IsDead
标志(如果使用处置模式,则可以使它成为标志IsDisposed
)-实际上,您根本不需要维护“死列表”。
最好在每个项目上使用标记以提高性能,因为您不必在列表中进行搜索以进行删除。而且对于设计而言,它也是更可取的-这意味着每个对象都可以轻松检查它是否已死-因此您不会意外地在其上调用任何方法(如果这些对象正在实现一次性模式,则ObjectDisposedException
在这种情况下它们可能会抛出)。
如果您有个集合,而不是List<>
,则从该集合中删除无效项目可能仍会涉及创建无效列表(因为在迭代过程中可能无法删除)。以我的观点,从设计的角度来看,最好是在死列表被使用之前创建一个死列表,方法是遍历该集合以寻找IsDead
标志,而不是尝试在杀死对象时维护该列表。
一旦完成了死列表,就应该将Clear()
其保留,然后保留它以备后用。
IsDead
模式在功能上与相同IsDisposed
。语义上的使用IsDead
意味着您正在维护这些对象的“绘制/更新”列表,这些列表将在以后将其从中删除。处置方式并不意味着这一点。此外,处置模式确实意味着该对象可能拥有不受管的资源(通常不适用于游戏对象)。
99.9%的时间,垃圾收集器(GC)会处理所有事情,而不会带来麻烦。删除/清空这些对象后,只需让其执行工作即可。清理中的延迟取决于许多因素(例如分配了多少内存块),但是您通常甚至不需要知道这一点,更不用说担心了。它旨在工作。这是您使用C#而不是C的原因之一。
一般来说,GC性能,不要过分担心自己,除非您偶然(通过分析)知道它正在造成瓶颈-通常,这仅在要求非常严格的游戏中才会出现。如果是这种情况,请查看GC.Collect()及其各种陷阱,以便知道何时使用它是合适的。我建议使用谷歌搜索“ force gc xna”,那里有很多资料。