这是一个锁定每秒60个循环的循环的好方法吗?

时间:2014-03-24 15:10:56

标签: c++ algorithm loops timer

我有一个以Bullet Physics作为物理引擎的游戏,游戏是在线多人游戏,所以我尝试Source Engine approach通过网络处理物理同步。所以在客户端我使用GLFW所以默认情况下fps限制在那里工作。 (至少我认为这是因为GLFW)。但是在服务器端没有图形库,所以我需要锁定"模拟世界并将物理引擎踩到60" ticks"每秒。

这是锁定循环每秒运行60次的正确方法吗? (A.K.A 60" fps")。

void World::Run()
{
    m_IsRunning = true;

    long limit = (1 / 60.0f) * 1000;
    long previous = milliseconds_now();

    while (m_IsRunning)
    {
        long start = milliseconds_now();
        long deltaTime = start - previous;
        previous = start;

        std::cout << m_Objects[0]->GetObjectState().position[1] << std::endl;

        m_DynamicsWorld->stepSimulation(1 / 60.0f, 10);

        long end = milliseconds_now();
        long dt = end - start;

        if (dt < limit)
        {
            std::this_thread::sleep_for(std::chrono::milliseconds(limit - dt));
        }
    }
}

是否可以使用 std :: thread 执行此任务?

这种方式是否足够有效?

物理模拟每秒会被踩60次吗?

P.S

milliseconds_now()看起来像这样:

long long milliseconds_now()
{
    static LARGE_INTEGER s_frequency;
    static BOOL s_use_qpc = QueryPerformanceFrequency(&s_frequency);
    if (s_use_qpc) {
        LARGE_INTEGER now;
        QueryPerformanceCounter(&now);
        return (1000LL * now.QuadPart) / s_frequency.QuadPart;
    }
    else {
        return GetTickCount();
    }
}

取自:https://gamedev.stackexchange.com/questions/26759/best-way-to-get-elapsed-time-in-miliseconds-in-windows

1 个答案:

答案 0 :(得分:1)

如果要将渲染限制为最大FPS为60,则非常简单:

每一帧,只检查游戏是否运行得太快,如果是这样,只需等待,例如:

while ( timeLimitedLoop )
{
    float framedelta = ( timeNow - timeLast )
    timeLast = timeNow;

    for each ( ObjectOrCalculation myObjectOrCalculation in allItemsToProcess )
    {
        myObjectOrCalculation->processThisIn60thOfSecond(framedelta);
    }

    render(); // if display needed
}

请注意,如果启用了垂直同步,渲染将仅限于垂直刷新的频率,可能是50或60 Hz。

但是,如果您希望逻辑锁定在60fps,那就不同了:您必须以最大60 fps的逻辑运行方式隔离显示和逻辑代码,并修改代码以便你可以有一个固定的时间间隔循环和一个可变的时间间隔循环(如上所述)。要查看的好消息来源是“固定时间步长”和“可变时间步长”(Link 1 Link 2以及旧的可靠Google搜索。)

请注意您的代码: 因为您在1/60秒的整个持续时间内使用睡眠 - 已经过了时间,您可以轻松地错过正确的时间,将睡眠更改为循环运行,如下所示:

而不是

if (dt < limit)
        {
            std::this_thread::sleep_for(std::chrono::milliseconds(limit - dt));
        } 

更改为

while(dt < limit)
        {
            std::this_thread::sleep_for(std::chrono::milliseconds(limit - (dt/10.0)));
            // or 100.0 or whatever fine-grained step you desire
        }

希望这会有所帮助,但是如果您需要更多信息请告诉我:))