在尝试在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;
}
我用几个不同的计时器看到了这一事实,这使我相信我的实现或系统有问题。该示例在VS中运行,但我在独立发行版exe中也看到了。发挥更新率或抽奖中完成的工作量可能会帮助您显示出来。
测试完我的后台程序后,我发现一个奇怪的相关性。仅当在chrome中打开Spotify网络播放器并且大约每秒发生一次时,才会发生此跳过问题。
我发现这则帖子可能与以下内容有关: https://community.spotify.com/t5/Other-Partners-Web-Player-etc/Web-Player-on-Chrome-causes-lag-stutter/td-p/4587103
答案 0 :(得分:8)
关于典型的应用程序,也许我不了解吗? Windows是否需要经常劫持CPU周期吗?
是的,绝对如此。 Windows一次运行很多进程。现在,您的应用程序出现并执行本质上是繁忙的自旋循环。在某个时候,操作系统可能会取消优先级,这比您预期的要长,因为它看起来像是很长的计算,并且操作系统需要给其他进程相当的CPU时间份额。
通常,您不应该依赖于每秒调用绘制例程的确切次数,并且游戏的主时钟应该能够应对跳帧。我对SFML不熟悉,因此无法对此发表评论。
但是,我确实有实时音频(和相关视频)以每秒超过1000次更新的循环运行的经验。您可以通过将线程优先级设置为THREAD_PRIORITY_HIGHEST或THREAD_PRIORITY_TIME_CRITICAL(请参见SetThreadPriority)来改善游戏循环时间份额。
要使此方法有效,您还应该成为行为良好的应用程序,并定期执行某种等待。等待使操作系统可以执行必要的任务切换,以服务其他进程(其中几个优先级也很高,并且通常比您作为用户空间应用程序所能承受的要高)。
一个明显的等待位置是在下一个绘制循环之前。无需计算具有100%内核利用率的计时器,只需简单地计算您准备等待并调用std::this_thread::sleep_for
的时间。请记住,唯一的保证就是睡眠时间至少您指定的时间。它绝对可以而且将不止于此。但我建议您从那里开始并做一些实验。
答案 1 :(得分:3)
除了@paddy的答案外,我建议您调查fixed timesteps。如果这样做不值得麻烦,那么您还应该注意SFML具有Window.setFramerateLimit()
。它不是很精确,但是大多数简单的游戏并不需要很高的精度。
答案 2 :(得分:1)
我在1 KHz控制环路上使用了自旋环路加良率,但效果很好,但是可能会错过最后期限(数千个周期一次,还需要很长的睡眠时间)。
答案 3 :(得分:0)
最初看似问题是由我的防病毒软件引起的,但我认为我实际上已经缩小了范围,以发现Web播放器处于打开状态并导致性能峰值提高1 /秒。我不确定为什么会这样。