如何在c#中实现精确的游戏循环帧限制

本文关键字:游戏 循环 实现 | 更新日期: 2023-09-27 18:19:21

我正在尝试在c#编写的游戏引擎中实现游戏循环帧限制器。我被告知Thread.Sleep甚至需要几毫秒来执行Thread.Sleep(0),并且会稍微错过目标毫秒。因此,它不够精确,因为目标帧率可能需要引擎等待1毫秒。我不确定我应该在这使用Thread.SpinWait,因为也可能存在引擎需要等待10毫秒的情况,我不知道在这种情况下使用SpinWait是否是个坏主意。

这里有一段代码来说明我想要实现的目标:

public void Run()
{
    var targetDelta = TimeSpan.FromSeconds(0.016);
    Running = true;
    while (Running)
    {
        // Calculate time since previous frame start here ("delta")
        // Simplified, but essentially this is what's going on
        Input.HandleEvents();
        Scene.Update(delta);
        Renderer.Render(Scene);
        // Perform waiting to limit frame rate here
    }
}

如何在c#中实现精确的游戏循环帧限制

看,这就是你需要自己做测试的地方,看看实际发生了什么,而不仅仅是相信别人的话。

运行1000000通过一个循环来测量Thread.Sleep(0)所花费的时间,我得到每次执行的平均时间为2.44微秒,最小为1.70微秒,最大为6.49毫秒。虽然最后一个数字听起来像是一个问题,但实际上并不是。在100万次传递中,只有59次(0.0059%)的传递时间在1毫秒以上。

调用Thread.Sleep(0)的目的是将剩余的时间片释放回系统供其他进程使用。它可以防止进程在不需要的时候占用所有可用的CPU时间。

它不是特别准确,因为它受任务调度器的支配。但是,系统中的所有东西都是。如果没有在一个或多个核心上以实时优先级运行,您将无法获得更好的准确性。

您可以使用混合解决方案,当等待时间超过几毫秒时调用Thread.Sleep(0),然后在等待Stopwatch或类似的时间在最后几微秒内滴答时执行忙循环。