XNA计时如何工作?

XNA如何保持一致且精确的60 FPS帧速率? 此外,如何在不将CPU固定在100%的情况下保持如此精确的时序?

我不知道XNA是如何做到的,但几年前在使用OpenGL时,我使用一些非常简单的代码完成了同样的事情。

在它的核心,我假设XNA有某种渲染循环,它可能或可能不与标准的偶数处理循环集成,但为了举例,我们假设它不是。 在这种情况下,你可以写一些像这样的东西。

TimeSpan FrameInterval = TimeSpan.FromMillis(1000.0/60.0); DateTime PrevFrameTime = DateTime.MinValue; while(true) { DateTime CurrentFrameTime = DateTime.Now; TimeSpan diff = DateTime.Now - PrevFrameTime; if(diff < FrameInterval) { DrawScene(); PrevFrameTime = CurrentFrameTime; } else { Thread.Sleep(FrameInterval - diff); } } 

实际上你可能会使用像Environment.Ticks而不是DateTimes这样的东西(它会更准确),但我认为这说明了这一点。 这应该只调用drawScene大约每秒60次,其余时间线程将处于hibernate状态,因此不会产生任何CPU时间。

虽然上面的luke代码是理论上正确的,但使用的方法和属性并不是最佳选择:

  • 由于DateTime.Now的精度仅为约30ms(参见C#DateTime.Now精度并给出或取20ms),因此不建议将其用于高性能时序(60 FPS为16ms)。 System.Diagnostics.Stopwatch是实时.NET的首选计时器
  • Thread.Sleep遇到相同的精度/分辨率问题,并且无法保证仅在指定时间内hibernate

当前的XNA FX似乎挂钩到Windows消息循环并执行其内部预更新的每一步并仅在自上次更新以来经过的时间与指定的帧速率匹配时调用Game.Update (例如,默认设置每个16ms)。 如果您想真正了解XNA FX如何完成工作Reflector是您的朋友:)

随机花絮:回到XNA GameStudio 1.0 Alpha / Beta时间框架中有不少关于“完美的WinForms游戏循环”的博客post,虽然我现在找不到它们……

游戏应该以60fps运行,但这并不意味着它们会。 这实际上是发布游戏的上限。

如果你在调试模式下运行游戏,你可以获得更高的每秒帧数 – 例如,我的笔记本电脑在调试模式下的空白启动器模板运行时间超过1,000fps。

可以说,发布游戏中的XNA框架将尽力以60fps运行 – 但是您在项目中包含的代码有可能降低性能。 例如,有一些东西不断点燃垃圾收集,你通常会看到游戏的fps下降,或者在更新或绘制方法中抛出一些复杂的数学 – 因此让它们每一帧都开火……这通常会有点过分。 为了让您的游戏尽可能精简,需要注意很多事项。

如果你问XNA框架是如何实现这种上限的 – 我无法解释 – 但我可以说,这取决于你如何布局你的代码 – 你可以做什么肯定会对这个数字产生负面影响,而且它并不总是需要与CPU有关。 在垃圾收集的例子中,它只是清理一个RAM,它可能根本不显示CPU使用率的峰值 – 但可能会影响你的FPS,具体取决于垃圾量和它必须运行的间隔。

你可以在这里阅读XNA计时器如何实现的所有内容XNA Game Studio中的游戏计时但基本上它会在再次继续循环之前尝试1/60秒,同时请注意在渲染之前可以多次调用更新如果XNA需要“赶上”。