[英]SDL_Delay messing with SDL_GetTicks
我正在使用 SDL 開發一個簡單的節奏游戲,但我一直在跟蹤游戲中的時間(滴答聲)。 為了讓自己的生活更簡單,我想將 FPS 限制在 60,但是使用 SDL_Delay() 會影響 SDL_GetTicks(),這很奇怪。 SDL_GetTicks() function 不應該返回初始化的時間(包括在 SDL_Delay 中花費的時間)嗎? 我試圖用 std::chrono 做一些事情,但我無法理解計算時間。 我有一個想法用線程做一些事情,但我覺得有一種更簡單的方法。
不確定這是否是您要尋找的,但我認為值得一試。
由於實際時間和游戲時間之間通常不存在 1:1 的對應關系,因此有必要實現一個考慮游戲經過時間的“機制”。
在處理幀率時我更喜歡實現的方法是以下之一:
假設您希望將幀速率限制為 60FPS。 這意味着您的游戲必須每 1000 毫秒(1 秒)的 60 次更新一次。
為了實現這一點(並嘗試將 FPS 鎖定在一個近似固定的值),您可以測試渲染前一幀需要多長時間並相應地調整傳遞給SDL_Delay()
的值。 此外,您可以使用累加器來獲得更接近 60 FPS(而不是 62)的速度。
下面是一個用 C 編寫的示例,可以很容易地移植到 C++ 中。
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),因此游戲模擬在任何一幀都不會向前跳得太遠。
這是一個實現它的例子。
游戲 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.