C# XNA计时是如何工作的?

C# XNA计时是如何工作的?,c#,xna,C#,Xna,XNA如何保持一致且精确的60 FPS帧速率?此外,它如何在不将CPU固定在100%的情况下保持如此精确的定时?我不知道XNA是如何做到的,但几年前在使用OpenGL时,我使用一些非常简单的代码完成了同样的事情 在它的核心,我假设XNA有某种渲染循环,它可能与标准的偶数处理循环集成,也可能不集成,但为了示例起见,我们假设它不是。在这种情况下,你可以这样写 TimeSpan FrameInterval = TimeSpan.FromMillis(1000.0/60.0); DateTime Pr

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);
    }
}
TimeSpan FrameInterval=TimeSpan.FromMillis(1000.0/60.0);
DateTime PrevFrameTime=DateTime.MinValue;
while(true)
{
DateTime CurrentFrameTime=DateTime.Now;
TimeSpan diff=日期时间.Now-PrevFrameTime;
如果(差异<帧间隔)
{
DrawScene();
PrevFrameTime=CurrentFrameTime;
}
其他的
{
线程睡眠(帧间隔-差异);
}
}

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

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

如果你在调试模式下运行一个游戏,你可以获得更高的每秒帧数——例如,在调试模式下,我的笔记本电脑上的空白启动模板运行速度远远超过1000fps

也就是说,发布的游戏中的XNA框架将尽最大努力以60fps的速度运行,但项目中包含的代码有可能降低该性能。例如,让某些东西不断激发垃圾收集,你通常会看到游戏的fps下降,或者在更新或绘制方法中抛出一些复杂的数学-因此让它们激发每一帧..这通常有点过分。有许多事情要记住,以保持您的游戏尽可能精简


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

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

  • 由于日期时间的精度。现在仅为30毫秒左右(请参阅并给出或获取20毫秒),因此不建议将其用于高性能计时(60 FPS为16毫秒)。是
  • Thread.Sleep
    会遇到同样的精度/分辨率问题,并且不能保证只在指定的时间内睡眠
当前XNA FX似乎连接到Windows消息循环中,并在每个步骤执行其内部预更新,并调用
Game.update
,前提是自上次更新以来经过的时间与指定的帧速率匹配(例如,默认设置为每16毫秒)。如果你真的想知道XNA FX是如何完成这项工作的,那么你的朋友是:)


随机花絮:在XNA GameStudio 1.0 Alpha/Beta时间框架中,有很多关于“完美WinForms游戏循环”的博客帖子,尽管我现在找不到它们…

你可以阅读所有关于XNA计时器是如何在这里实现的,但基本上,它会在继续循环之前尝试运行1/60秒,还请注意,如果XNA需要“赶上”,则可以在渲染之前多次调用更新。我通常想知道任何常规计时是如何做到这一点的。但是通过使用Thread.Sleep,它不依赖于线程调度吗?这似乎是可以预测的。这就是为什么我想知道它们是如何做到如此一致的。使用线程睡眠确实让你任由调度程序摆布,但从长远来看,它应该相当平均,特别是在每秒60帧之后。当涉及到计算机上的高精度计时时,你无论如何都要受调度程序的摆布,因为你的线程随时都可能被调出。在这个答案中,你在很多方面都是错的。。。调试模式会导致更多的开销,而不是更少。代码降低性能并不是“偶然的”;永远都会。垃圾收集总是影响CPU,周期。