使用 delta 变量将 while 循环限制为 30 "FPS"运行C++

Limit while loop to run at 30 "FPS" using a delta variable C++

本文关键字:FPS C++ 运行 变量 delta while 循环 使用      更新时间:2023-10-16

我基本上需要一个while循环来仅以30"FPS"运行。我被告知要这样做:"在你的 while 循环中,创建一个 deltaT ,如果该 deltaT 小于 33 毫秒,请使用 sleep(33-deltaT)。"

但我真的不太确定如何初始化增量/将此变量设置为什么。我也无法从提出这个建议的人那里得到回复。

我也不确定为什么睡眠中的值是 33 而不是 30。

有谁知道我能做些什么吗?

这主要是为了让游戏服务器以 30FPS 的速度更新玩家,但由于我没有在服务器上进行任何渲染,所以我需要一种方法让代码休眠来限制它每秒可以运行的次数,否则它会处理玩家太快。

你基本上需要做这样的事情:

int now = GetTimeInMilliseconds();
int lastFrame = GetTimeInMilliseconds();
while(running)
{
    now = GetTimeInMilliseconds();
    int delta = now - lastFrame;
    lastFrame = now;
    if(delta < 33)
    {
        Sleep(33 - delta);
    }
    //...
    Update();
    Draw();
}

这样,您可以计算当前帧和最后一帧之间经过的毫秒数,如果它小于 33 毫秒(1000/30,每秒 1000 毫秒除以 30 FPS = 33.333333...),那么您将一直睡到 33 毫秒过去。具有GetTimeInMilliseconds()Sleep()功能,这取决于您使用的库和/或平台。

c++11 为此提供了一个简单的机制:

#include <chrono>
#include <thread>
#include <iostream>
using namespace std;
using namespace std::chrono;
void doStuff(){
    std::cout << "Loop executed" << std::endl;
}
int main() {
    time_point<system_clock> t = system_clock::now();
    while (1) {
        doStuff();
        t += milliseconds(33);
        this_thread::sleep_until(t);
    }
}

不过,您唯一需要注意的是,如果一个循环迭代花费的时间超过 33ms,则接下来的两次迭代将在中间没有暂停的情况下执行(直到 t 赶上实时),这可能是也可能不是您想要的。

Glenn Fiedler几年前写了一篇关于这个话题的好文章。使用sleep()进行黑客攻击不是很精确,相反,您希望每秒运行固定次数的物理效果,让您的图形自由运行,并且在帧之间,您可以执行尽可能多的固定时间步长。

下面的代码起初看起来很吓人,但一旦你明白了这个想法,它就变得简单了;最好完整地阅读这篇文章。

修复您的时间步长

double t = 0.0;
double dt = 0.01;
double currentTime = hires_time_in_seconds();
double accumulator = 0.0;
State previous;
State current;
while ( !quit )
{
    double newTime = hires_time_in_seconds();
    double frameTime = newTime - currentTime;
    if ( frameTime > 0.25 )
        frameTime = 0.25;
    currentTime = newTime;
    accumulator += frameTime;
    while ( accumulator >= dt )
    {
        previousState = currentState;
        integrate( currentState, t, dt );
        t += dt;
        accumulator -= dt;
    }
    const double alpha = accumulator / dt;
    State state = currentState * alpha + 
        previousState * ( 1.0 - alpha );
    render( state );
}

如果它离线,应该有几个备份可用;但是,我记得Gaffer on Games已经很多年了。