XNA游戏性能

16

我正在使用C# 2010和XNA 4.0编写一款游戏。我希望它是一个好游戏,而不只是"又一个垃圾游戏",因此我的目标之一是良好的帧率。为此,我想请你给出一些建议,不管是与XNA相关还是与C#相关 - 我该如何加速代码以提高FPS。

以下是我发现的一些东西:

  • (c#) 使用 array 而不是 list<> 可以大大提高性能,如果您要访问大量数据(甚至很多: 有20000个项目的数组比20000个列表的FPS高了近180%)。
  • (c#) 使用 for 而不是 foreach 会提高性能。在相同的20000个元素上,差异约为5-10%。
  • (xna和c#) 调用方法会消耗性能,因此当我将代码散布到方法中并调用其他方法时,一切都很酷和面向对象,但每次调用的成本都是1-3 FPS。
  • (xna) 更新 vs 绘图: 当我将代码放入update()和draw()中时,性能没有区别,因此如果您不太在意,您不必将某些方法放在update()中,而是将所有内容保持在draw()中,希望获得更好的FPS。
  • (xna) 不知道是不是我自己或只是4.0,但当您加载了一个带有大量纹理和相当复杂的网格的.X文件时,需要很长时间才能加载。我不得不编写自己的.X加载器和网格/模型渲染器,因为XNA开始为每个三角形加载纹理,而不管前一个三角形是否具有相同的纹理。即使编写自己的contentloader来缓存纹理也不是解决方案,因为它仍然被频繁使用。如果您打算制作柔软漂亮的东西,我建议使用drawuserprimitives而不是Model类。(不知道是否仅限于4.0,还是3.1也存在这样的性能问题)
  • (XNA和C#) 在绘图时尽量避免使用 "new"。我在网上看到一些代码被复制/粘贴在一起,并在draw()中出现"basicEffect = new BasicEffect(graphicsDevice);"这样的丑陋代码,甚至更糟糕的是,在draw()内部的迭代中也会出现这种情况。这会降低性能。而不是这样,在游戏中或静态类中拥有一个此类对象。这也适用于其他“临时对象”:虽然丑陋,但我认为创建一个全局对象并小心使用它比编写漂亮且臃肿的代码更好,因为后者会使我们的游戏因垃圾回收器而减缓。
  • 总之,要让我们能够制作出好、快、优化的游戏,请遵循以下建议:

    • 在绘制时尽可能避免使用 "new"。
    • 将上述类放置在游戏类或静态类中。
    • 对于其他“临时对象”,请创建全局对象并小心使用。

    感谢您的阅读和理解:Zéiksz


    1
    我建议将这个设为社区维基。 - Jess
    5
    我不相信使用扎实的面向对象架构每次调用都会损失1-3帧。 - Blindy
    2
    GC与此有什么关系?如果您使用相同的对象,则无论是在单个函数中还是不在单个函数中,都将分配相同的内存。函数不会被垃圾回收。 - Blindy
    2
    我要注意的是,foreach 可以根据集合使用 IEnumerawhatever<> 接口,这可能会触发 GC。但是关于将代码结构化为方法的部分并不合理。编译器应该在适当的情况下进行内联,并且即使它没有内联,您也可以强制执行它。 - Dave
    @Blindy 我并不支持Zeiksz的说法,而且我也没有深入研究过这个问题,但是使用一台不错的电脑配置,XNA可以以数千帧每秒的速度进行渲染(我认为我的电脑在什么都不画的情况下就能达到大约10k FPS;这是使用一张2009年的HD 5850显卡)因此,为了一个函数调用而减少1 FPS或许并不是那么难以置信。 - FreeAsInBeer
    显示剩余6条评论
    3个回答

    8
    软件优化是一门手艺。最好的优化是基于收集到的统计数据的证据。
    在没有问题之前不要进行优化。您不认为游戏的可玩性比这个指标或那个指标更重要吗?我的建议是先开发游戏,然后考虑它在哪些方面表现不佳。
    然后提出一些具体的问题,我相信您一定会在这里得到一些帮助。
    同时,我建议您从像这里列出的游戏开发书籍中获取更多信息。 XNA Extereme 101 - 似乎是一个有趣的教程。

    我同意预先进行编程优化不是好方法。但我认为为遇到此问题的人提供问题/答案会很有帮助。 - Erik Philips
    @erik - 我也同意。这是一个收集这些信息的好地方。 - Preet Sangha
    +1 我完全同意这个答案。遇到性能问题的人几乎肯定是在做一些严重错误的事情,应该运行分析器来找到问题,或者发布有关具体问题的帖子。如果你有问题,合并一半的方法调用是不会有帮助的。 - John McDonald
    1
    谢谢您的建议,但我仍然认为在实施其他方法之前了解某些内容比事后进行优化并可能需要全面改进更好。我问问题是想知道在编程时要注意什么。 - Zéiksz

    8

    我的两分钱建议:

    不要将所有的代码都放在一个方法中,因为你认为调用方法会导致成本增加。如果你认为通过调用空方法来减少1-3帧每秒,那么你可能还没有完全研究这种损失。要在调用一个空方法时出现这种损失,你必须有上千个FrameRate...在那里你不会担心1-3的下降。

    FPS是评判XNA性能的不好方式。当你启用可变时间步长时,操作系统涉及到的其他进程可以影响你的帧率。你需要进行性能分析。仅集中于使用System.Diagnostic.Stopwatch对象计时实际完成Update和/或Draw方法所需的时间。分别计时,不要一起(非常重要)。

    'new'关键字不仅应该在绘制调用中避免,在更新和绘制中的任何地方都应该避免使用...仅适用于引用类型。使用new关键字时,无论何时何地都需要使用值类型。


    7

    6
    截止到12年8月24日,该网站似乎已经停止运营。 - Inisheer

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