c++ - Steady_Clock 在主游戏循环的更新之间跳过

标签 c++ game-engine clock game-development game-loop

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

问题: 在某种程度上,我经常看到更新之间能够完成的工作量有所跳跃。每次更新应该花费 1/60 秒,其余时间花在 Draw() 上,尽可能多地完成绘图。 有时,平局数量会无缘无故地下降到 0 或 1。这会以明显的口吃形式出现在实际应用程序中。除了“跳过”之外,完成的抽奖次数非常一致。

这是一张图片(注意更新时间的跳跃和绘制的下降): Console output of the issue

部分代码:

#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;
}
  • 也许我对典型应用程序有一些不了解的地方? Windows 是否需要经常劫持 CPU 周期?
  • 我在 steady_clock、clock 和充实的 SFML 应用程序中看到过这个问题,该应用程序的工作是在更新和绘制期间完成的
  • 我假设 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

最佳答案

Perhaps there is something I don't understand about typical applications? Does Windows need to hijack CPU cycles every so often?

是的,绝对是。 Windows 正在同时运行大量进程。现在您的应用程序出现并执行本质上是一个繁忙的自旋循环。在某些时候,操作系统可能会降低其优先级的时间比您预期的要长,因为它看起来像是一个漫长的计算,并且操作系统需要为其他进程提供公平份额的 CPU 时间。

一般来说,您不应该依赖每秒调用精确次数的绘图例程,并且您的游戏的主时钟应该能够处理跳帧。我不熟悉 SFML,所以我不能对此发表评论。

但是,我确实有过在每秒超过 1000 次更新的循环中运行实时音频(以及与此相关的视频)的经验。您可以通过将线程优先级设置为 THREAD_PRIORITY_HIGHEST 或 THREAD_PRIORITY_TIME_CRITICAL 来改善游戏循环时间份额(参见 SetThreadPriority)。

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

等待的明显位置是在您的下一个抽奖周期之前。与其以 100% 的核心利用率启动计时器,不如简单地计算您准备等待的时间并调用 std::this_thread::sleep_for .请记住,唯一的保证是 sleep 至少您指定的时间。它绝对可以而且将不止于此。但我建议您从这里开始并做一些实验。

关于c++ - Steady_Clock 在主游戏循环的更新之间跳过,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53735418/

相关文章:

c# - 同步两个日期时间

c++ - 为什么要把 std::lock 放在 std::lock_guard 之前

c++ - 对如何在 c++ 中编写 for 循环(包括 for all 加法)感到困惑

声明模板类后的 C++ 链接器错误

math - Three.js 精准地形碰撞

使用 clock() 函数计算 C 中 system() 命令的运行时间

android - AOSP : where can I find the layout of the new clock (fonts and size)?

c++ - 设置用于打印 C++ 的 GDI 页面设置

c++ - 避免在默认模板中使用尖括号

c++ - 如何在 Cocos2d-x 3.15.1 中避免 MenuItemImage 和 MenuItemSprite 冲突