簡體   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