有效消除游戏中的死物?


10

我正在使用for循环或foreach循环(无关紧要)来遍历所有需要更新或绘制的对象。但是,当某个对象被杀死时,我希望它再次从集合中删除。

为此,我将对象添加到一个死对象列表中,然后,在绘制并更新了所有内容之后,我将遍历此列表中的所有内容,并将列表中的对象也从原始源中删除。

有更好的方法吗?



2
尽管标题中使用了“ garbage”一词,到目前为止,提到的是.NET Garbage Collector,但实际上这与垃圾收集无关。
安德鲁·罗素

为了避免与.NET垃圾收集器混淆,我冒昧地将“垃圾”一词实际上更改为“死”。
没关系,

哦,我知道。垃圾回收文章仍然很重要,因为它可能会影响您处理那些死对象的工作。例如死角?将其与所有内容断开链接,将其重置为默认设置,放回垃圾桶。
doppelgreener 2011年

Answers:


11

首先:术语。如果您说“垃圾清单”,人们会认为您在谈论垃圾收集器。我们称其为“死名单”。

正如您可能已经发现的,因此是您的问题,在迭代集合时,您无法从集合中删除项目。如果您的收藏集是一种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意味着您正在维护这些对象的“绘制/更新”列表,这些列表将在以后将其从中删除。处置方式并不意味着这一点。此外,处置模式确实意味着该对象可能拥有不受管的资源(通常不适用于游戏对象)。
安德鲁·罗素

您可以使用反向使用foreach做到这一点。
shinzou

0

99.9%的时间,垃圾收集器(GC)会处理所有事情,而不会带来麻烦。删除/清空这些对象后,只需让其执行工作即可。清理中的延迟取决于许多因素(例如分配了多少内存块),但是您通常甚至不需要知道这一点,更不用说担心了。它旨在工作。这是您使用C#而不是C的原因之一。

一般来说,GC性能,不要过分担心自己,除非您偶然(通过分析)知道它正在造成瓶颈-通常,这仅在要求非常严格的游戏中才会出现。如果是这种情况,请查看GC.Collect()及其各种陷阱,以便知道何时使用它是合适的。我建议使用谷歌搜索“ force gc xna”,那里有很多资料。


因此,如果我每次都有一个在Update()调用中使用的列表,该列表中元素为“ null”的所有元素都将自动清除并删除?
Mathias Lykkegaard Lorenzen 2011年

@Mathias不。请参阅我对您问题的评论。垃圾收集器不会修改您仍然可以访问的任何内容-包括您的集合及其内容。
安德鲁·罗素

1
这个问题与GC 没有任何关系,只是不幸地选择了“垃圾”一词。
没关系,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.