Steady_Clock在主游戏循环中的更新之间跳过

S. *_*age 11 c++ clock game-development game-engine game-loop

在试图在SFML中找到一个可靠的游戏循环的过程中,我遇到了这个我似乎无法弄清楚的问题.我能够删除所有SFML代码,仍然clock()在time.h中看到问题.然后我走得更远,仍然看到问题使用std::chrono::steady_clock.

问题:我总是看到跳过更新之间可以完成的工作量.每次更新应该花费1/60秒,剩下的时间用于Draw()尽可能多地完成绘图.有时抽奖量下降到0或1,没有明显的原因.这会以明显的口吃形式冒泡到实际应用中.除了"跳过"之外,完成的抽签次数非常一致.

这是一个图像(注意更新时间的跳转和绘制中的下降): 问题的控制台输出

一些代码:

#include <iostream>
#include <time.h>
#include <chrono>

using namespace std;
using namespace std::chrono;

void Draw()
{
    //for (int i = 0; i < 1000000; i++);
}

int main()
{
    steady_clock::time_point update_time;
    steady_clock::time_point update_next;
    int update_rate = 16666666; // 60 times a second (nanosecs)
    int updates;
    int max_updates = 5;
    int draws = 0;
    update_next = steady_clock::now();

    while (true)
    {
        updates = 0;
        update_time = steady_clock::now();
        while (duration_cast<nanoseconds>(update_time - update_next) > nanoseconds(update_rate) && updates++ < max_updates)
        {
            if (draws <= 1) {
                cout << "!!!!!!!!!!!!!ERROR!!!!!!!!!!!!!" << endl;
            }
            cout << "UPDATE - ";
            cout << "Draws: " << draws 
                 << " - UT - UN: " << duration_cast<nanoseconds>(update_time - update_next).count()
                 << endl;

            draws = 0;
            update_next += nanoseconds(update_rate);
        }
        draws++;
        Draw();
    }

    return 0;
}
Run Code Online (Sandbox Code Playgroud)
  • 也许有些东西我不了解典型的应用程序?Windows是否需要经常劫持CPU周期?
  • 我已经看到了这个问题,包括steady_clock,clock和一个充实的SFML应用程序,其中工作在Update和Draw期间完成
  • 我假设SFML时钟可能使用time.h时钟
  • 从我的测试来看,max_updates检查与此问题无关(我认为它们不会导致问题)

我用几个不同的计时器看到这个的事实让我相信我的实现或我的系统有问题.这个例子是在VS中运行的,但我也在一个独立的发行版exe中看到过它.玩更新率或抽奖工作量可能有助于它出现.


在测试我的后台进程后,我发现了一个奇怪的相关性.仅当Spotify网络播放器以chrome格式打开并且每秒钟发生一次时,才会出现此跳过问题.

我发现这篇文章可能有关:https: //community.spotify.com/t5/Other-Partners-Web-Player-etc/Web-Player-on-Chrome-causes-lag-stutter/td-p/4587103

pad*_*ddy 8

也许有些东西我不了解典型的应用程序?Windows是否需要经常劫持CPU周期?

是的,一点没错.Windows一次运行大量进程.现在你的应用程序出现并执行本质上是繁忙的自旋循环.在某些时候,操作系统可能会将此优先级排除在预期之外的时间超出预期,因为它看起来只是一个长时间的计算,并且操作系统需要为其他进程提供相当长的CPU时间.

一般来说,你不应该依赖你的绘图程序被称为每秒的确切次数,并且你的游戏的主时钟应该能够处理跳过的帧.我不熟悉SFML所以我不能对此发表评论.

但是,我确实拥有在每秒超过1000次更新的循环中运行的实时音频(以及视频)的经验.您可以通过将线程优先级设置为THREAD_PRIORITY_HIGHEST或THREAD_PRIORITY_TIME_CRITICAL来提高游戏循环时间份额(请参阅SetThreadPriority).

为了使其有效,您还应该是一个表现良好的应用程序并定期执行某种等待.等待允许操作系统执行必要的任务切换以服务其他进程(其中一些进程也将是高优先级,并且通常高于您将能够作为用户空间应用程序强制执行的进程).

等待的明显位置是在下一个绘制周期之前.而不是使用100%核心利用率来旋转计时器,只需计算您准备等待和呼叫的时间std::this_thread::sleep_for.请记住,唯一的保证是睡眠将至少为您指定的数量.它绝对可以而且将会超过这一点.但我建议你从那里开始做一些实验.