繁体   English   中英

SDL_Delay 与 SDL_GetTicks 混淆

[英]SDL_Delay messing with SDL_GetTicks

我正在使用 SDL 开发一个简单的节奏游戏,但我一直在跟踪游戏中的时间(滴答声)。 为了让自己的生活更简单,我想将 FPS 限制在 60,但是使用 SDL_Delay() 会影响 SDL_GetTicks(),这很奇怪。 SDL_GetTicks() function 不应该返回初始化的时间(包括在 SDL_Delay 中花费的时间)吗? 我试图用 std::chrono 做一些事情,但我无法理解计算时间。 我有一个想法用线程做一些事情,但我觉得有一种更简单的方法。

不确定这是否是您要寻找的,但我认为值得一试。

由于实际时间和游戏时间之间通常不存在 1:1 的对应关系,因此有必要实现一个考虑游戏经过时间的“机制”。
在处理帧率时我更喜欢实现的方法是以下之一:

  • 将帧速率限制为固定值(例如 60 FPS);
  • 使用增量时间并据此更新游戏逻辑(作为增量时间的 function)。

限制“静态”帧率

假设您希望将帧速率限制为 60FPS。 这意味着您的游戏必须每 1000 毫秒(1 秒)的 60 次更新一次。
为了实现这一点(并尝试将 FPS 锁定在一个近似固定的值),您可以测试渲染前一帧需要多长时间并相应地调整传递给SDL_Delay()的值。 此外,您可以使用累加器来获得更接近 60 FPS(而不是 62)的速度。

下面是一个用 C 编写的示例,可以很容易地移植到 C++ 中。

C 示例:固定 60 FPS 上限

remainder是累加器

static void capFrameRate(long *then, float *remainder)
{
    long wait, frameTime;

    wait = 16 + *remainder; // 16 is the integer part of 1000/60

    *remainder -= (int)*remainder;

    frameTime = SDL_GetTicks() - *then; // time it took the previous frame to render

    wait -= frameTime;

    if (wait < 1)
    {
        wait = 1;
    }

    SDL_Delay(wait);

    *remainder += 0.667; // 0.667 is the fractional part of 1000/60

    *then = SDL_GetTicks();
}

主要的:

int main(int argc, char** argv)
{
    long then;
    float remainder;

    while (1)
    {
        // clear renderer
        
        // get input
        
        // update game logic

        // render frame
        
        capFramerate(&then, &remainder);
    }

    return 0;
}

使用增量时间

您可以跟踪自上一帧以来经过的游戏时间(即delta time )。
例如,如果您使用object.x += 5; ,object 的运动将取决于当前的帧率(由于许多通常不可预测的因素,可能会有所不同); 但是,如果我们使用增量时间,我们可以每秒更新 object position 一些像素: object.x += 5 * deltaTime; ,而 object 将始终每秒移动 5 个像素,即使帧速率上升到一个非常大的值。

帧限制:使用增量时间,您无需再延迟游戏。 但是,允许游戏以系统允许的任何帧速率运行可能会导致几个问题。 最简单的解决方案是实现帧限制机制,强制游戏循环等待目标增量时间过去。
例如,如果目标是 60 FPS,我们希望目标时间为每帧 16.667 毫秒(1000/60)。 然后我们可以使用SDL_TICKS_PASSED()宏来实现: while (,SDL_TICKS_PASSED(SDL_GetTicks(); mTicksCount + 16)); .

最后一件事,注意增量时间太长可能很有用,因为游戏可能会暂停(例如,在调试和单步执行断点时)。 要解决此问题,您可以将增量时间限制为最大值(例如 0.05f),因此游戏模拟在任何一帧都不会向前跳得太远。

这是一个实现它的例子。

C++ 示例:增量时间 + 60 FPS 帧限制 + 增量时间上限

游戏 class:

class Game
{
public:
    Game();
    void RunLoop();
private:
    // Stuff (window, renderer, ...)
    float deltaTime; // Delta time
    Uint32 mTicksCount; // Number of ticks since start of game

    // get input
    UpdateDeltaTime(); // Update delta time
    UpdateGameLogicExample(); // Update game objects as function of delta time
    // render frame
};

更新时间差的方法:

void Game::UpdateDeltaTime()
{
    // Frame limiting: wait until 16ms has elapsed since last frame
    while (!SDL_TICKS_PASSED(SDL_GetTicks(), mTicksCount + 16));

    // Delta time is the difference in ticks from last frame
    // (converted to seconds)
    deltaTime = (SDL_GetTicks() - mTicksCount) / 1000.0f;
    
    // Clamp maximum delta time value
    if (deltaTime > 0.05f)
    {
        deltaTime = 0.05f;
    }

    // Update tick counts (for next frame)
    mTicksCount = SDL_GetTicks();
}
void Game::UpdateGameLogicExample()
{
    gameObj.x += 5 * deltaTime; // Each second the game object will move by 5 pixel, independantly from the processor frequency or other external factors
}

游戏循环:

void Game::RunLoop()
{
    while (true)
    {
        // clear renderer

        // get input

        UpdateDeltaTime();

        UpdateGameLogicExample();

        // render frame
    }
}

一些有用的参考资料

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM