如何在XNA组件不在屏幕上时防止其绘制?

5
我在使用XNA制作2D游戏。在使用可绘制的游戏组件时,哪一种方法对性能更好呢?
1.当一个组件不在屏幕上时,从组件列表中将其移除,在屏幕上时再添加它。
2.当它不在屏幕上时,不要运行它的绘制函数(通过使用“awake”布尔字段和绘制函数周围的if语句)。
我目前正在使用方法2,它运行良好。这很方便,因为组件的绘制顺序不会改变(如果我删除并重新添加它们,则会更改,我需要更多的代码来管理它)。实际上,我刚刚意识到,如果它不在组件列表中,它就不会更新,我需要其他东西来跟踪它是否在屏幕上。
此外,我没有带有分析器的高级版本的Visual Studio,所以我只是在这里问问大家的经验是什么。

1
你不需要昂贵的分析器来确定测试中哪个更快,Stopwatch已经足够了。分析器将帮助解释为什么一个比另一个更快(即这个算法的哪些部分是慢的,什么消耗了最多的内存,我需要费心优化这个部分吗等)。 - Servy
2
我相信选择2会更快。 - Cyral
2
你使用了多少个DrawableGameComponent?如果你使用了很多实例,那么你可能在错误地使用它。 - Seth Battin
1
@Guye 你对这个问题更关心CPU性能还是GPU性能? - Steve H
@Seth - 是的,我正在使用很多可绘制的游戏组件。构成墙壁的每个块都是一个可绘制的游戏组件.. 你能否再详细解释一下? - Guye Incognito
显示剩余2条评论
1个回答

6
在使用SpriteBatch时,有一个有时被忽视的CPU性能概念,即如何批处理您的精灵。使用可绘制的游戏组件不容易有效地进行精灵批处理。
基本上,绘制精灵的GPU不慢,将所有精灵组织成一批的CPU也不慢。缓慢的部分是当CPU必须与GPU通信以告诉它需要绘制什么(发送批处理信息)时。当调用spriteBatch.Draw()时,此CPU到GPU通信不会发生。它发生在调用spriteBatch.End()时。因此,提高效率的低 hanging fruit 是尽可能少地调用spriteBatch.End()。(当然这意味着也要尽可能少地调用Begin())。另外,非常节俭地使用spriteSortMode.Imediate,因为它会立即导致CPU向GPU发送每个精灵的信息(很慢)。
因此,如果您在每个游戏组件类中调用Begin()和End(),并且有许多组件,则无谓地浪费了很多时间,并且您可能会节省更多时间来设计更好的批处理方案,而不必担心屏幕外的精灵。
此外:GPU自动忽略其像素着色器中的屏幕外精灵。因此,在CPU上裁剪屏幕外精灵不会节省GPU时间......

非常感谢!非常有启发性。另外,我想提一下,我的游戏是由房间组成的程序生成关卡。在编写任何性能代码之前,我进行了一个包含140个房间的压力测试,结果速度非常慢。然后我只绘制当前所在的房间(我的帖子中的方法2),性能恢复到完美状态。根据您的答案,这全部都是CPU造成的,这很有道理,因为它在一台性能较差的笔记本电脑上运行Visual Studio! :) 我想我会遵循您的建议重新设计一下,使我的开始和结束语句更加有效。 - Guye Incognito
我想说的是,仅仅因为你正在使用drawablegamecomponents,并不意味着你不能使用相同的spritebatch.begin()。如果你将base.draw放在spritebatch中,你可以从你的主Game文件调用begin,然后在你的组件中进行所有的绘制,最后在Game文件中再次调用spritebatch.end。 - TopHatHacker
@TopHatHacker 我本来想提到这个问题的,但后来意识到如果有一些3D可绘制组件和一些2D组件,那么这种方法就不适用了。 - Steve H

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接