【问题标题】:Using sleep() in game loop makes delta time unstable在游戏循环中使用 sleep() 会使增量时间不稳定
【发布时间】:2016-12-30 02:02:14
【问题描述】:

我正在使用 sfml 编写游戏循环。当我不让它休眠时,每次循环迭代所用的时间约为 1 毫秒。但是当我添加 sleep(sleepTime) 突然 dt 很高。我在循环开始时重新启动 dt 但似乎它增加了最后的睡眠时间。是什么原因造成的?

sf::Clock clock;
float dt;
sf::Time sleepTime = sf::milliseconds(0);

while(m_Window.isOpen())
{
    sf::Time elapsed = clock.restart();
    dt = elapsed.asMilliseconds();

    cout << "Elapsed: " << dt;

    sf::Event event;

    while(m_Window.pollEvent(event))
    {
        switch(event.type)
        {
            case sf::Event::Closed:
                m_Window.close();
                break;
        }
    }

    sleepTime = sf::milliseconds(16 - dt);

    float time = sleepTime.asMilliseconds();
    cout << "\tSleep time: " << time << endl;

    if(sleepTime >= sf::Time::Zero)
    {
        sf::sleep(sleepTime);
    }
    else
    {
        cout << "Shit." << endl;
    }

不睡觉:https://aww.moe/sn1z0a.png

带睡眠:https://aww.moe/7seof1.png

【问题讨论】:

  • 睡眠导致它。你为什么要睡觉?
  • 因为我想建立恒定的游戏速度。我正在使用这个:koonsolo.com/news/dewitters-gameloop 作为指南。
  • 而且我知道 sleep() 并不是非常准确。但是我在循环开始的时候重新启动了dt,为什么要给dt加上sleep时间呢?
  • 睡眠不会像恒定的游戏速度那样建立任何东西。这就是分时操作系统的本质。
  • 我不清楚 - 你期望什么样的输出?您为每次迭代轮询一次时钟,其中包括睡眠。那么为什么不应该把睡眠时间包括在这个读数中呢?也许您的意思是在计算 sleepTime 之前再次轮询时钟?

标签: c++ sfml game-loop


【解决方案1】:

您正在尝试做的事情——将游戏限制在特定的帧速率——已经内置在 SFML 中。只需调用 sf::Window::setFrameRateLimit() 并将您的预期帧速率作为参数,您就可以设置好了。也可以使用垂直同步(通过使用sf::Window::setVerticalSyncEnabled())来限制帧/更新的数量,尽管这通常被认为是一个坏主意,因为如果目标机器无法以所需的帧速率渲染游戏也会变慢(或加速以 120 或 140Hz 运行的高端屏幕)。

但是,您通常希望将游戏更新与帧速率断开连接,这样游戏就不会变慢,即使当前机器无法足够快地更新屏幕。

使用 SFML 的基本方法通常如下所示(来自记忆,因此可能包含错误或拼写错误):

sf::Clock updateTimer; // Clock to monitor the time passed
sf::Time passedTime; // Accumulated game time
const sf::Time frameTime(sf::milliseconds(10)); // intended time per frame; here: 10ms

while (window.isOpen()) {
    sf::Event event;
    while (window.pollEvent(event)) {
        // Event handling
    }

    // First add the time passed
    passedTime += updateClock.restart();

    unsigned int numUpdates = 0; // Count the updates done

    // As long as enough time passed, do an update
    // Up to a specific maximum to avoid problems, e.g.
    // the main thread was blocked or can't catch up
    while (passedTime >= frameTime) {

        if (numUpdates++ < 10) {
            // Do your game update here
        }

        // Subtract the time we've "handled"
        passedTime -= frameTime;
    }

    window.clear();
    // Draw your game here
    window.display();
}

numUpdates 的用法一开始可能不太清楚,但想象一下机器几乎无法每秒运行所需的 100 次更新的情况。如果你落后了 20 次更新(一些小问题或其他什么),机器将永远无法正常赶上,导致严重卡顿或游戏变得无响应。

【讨论】:

  • @Glamhoth 不要第二次重新启动计时器(最后)。否则,您将浪费绘制所有内容的时间。
猜你喜欢
  • 1970-01-01
  • 2022-10-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多