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

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

我基本上需要一个 while 循环才能在 30 "FPS" 处仅 运行。 有人告诉我这样做: "Inside your while loop, make a deltaT , and if that deltaT is lesser than 33 miliseconds use sleep(33-deltaT) ."

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

我也不确定为什么 sleep 中的值是 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() 功能,这取决于您使用的库 and/or 平台。

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

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

Fix Your Timestep

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 多年的游戏了。

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);
    }
}

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