0

我设法创建了一个允许游戏对象根据时间变化(而不是帧数变化)移动的系统。我现在,为了实践,试图强加一个 FPS 限制器。

我遇到的问题是发生的游戏循环数量是我预期的两倍。例如,如果我尝试将帧数限制为 1 FPS,那么 2 帧将在那一秒内通过 - 一个非常长的帧(约 1 秒)和 1 个极短的帧(约 15 毫秒)。这可以通过输出每个游戏循环之间的时间差(以毫秒为单位)来显示 - 示例输出可能是 993、17、993、16...

我尝试更改代码,以便在 FPS 受限之前计算增量时间,但无济于事。

定时器类:

#include "Timer.h"
#include <SDL.h>

Timer::Timer(void)
{
    _currentTicks = 0;
    _previousTicks = 0;
    _deltaTicks = 0;

    _numberOfLoops = 0;
}

void Timer::LoopStart()
{
    //Store the previous and current number of ticks and calculate the
    //difference. If this is the first loop, then no time has passed (thus
    //previous ticks == current ticks).
    if (_numberOfLoops == 0)
        _previousTicks = SDL_GetTicks();
    else
        _previousTicks = _currentTicks;

    _currentTicks = SDL_GetTicks();

    //Calculate the difference in time.
    _deltaTicks = _currentTicks - _previousTicks;

    //Increment the number of loops.
    _numberOfLoops++;
}

void Timer::LimitFPS(int targetFps)
{ 
    //If the framerate is too high, compute the amount of delay needed and
    //delay.
    if (_deltaTicks < (unsigned)(1000 / targetFps))
        SDL_Delay((unsigned)(1000 / targetFps) - _deltaTicks);
}

(部分)游戏循环:

//The timer object.
Timer* _timer = new Timer();

//Start the game loop and continue.
while (true)
{
    //Restart the timer.
    _timer->LoopStart();

    //Game logic omitted

    //Limit the frames per second.
    _timer->LimitFPS(1);
}

注意:我正在使用 SMA 计算 FPS;此代码已被省略。

4

2 回答 2

1

问题是如何设置计时器结构的一部分。

_deltaTicks = _currentTicks - _previousTicks;

我看了几次代码,根据你设置计时器的方式,这似乎是问题所在。

在代码开始时遍历它 _currentTicks 将等于 0 并且 _previousTicks 将等于 0 因此对于第一个循环,您的 _deltaTicks 将为 0。这意味着无论您的游戏逻辑如何,LimitFPS 都会出现异常。

void Timer::LimitFPS(int targetFps)
{ 
    if (_deltaTicks < (unsigned)(1000 / targetFps))
        SDL_Delay((unsigned)(1000 / targetFps) - _deltaTicks);
}

我们刚刚计算出 _deltaTicks 在循环开始时为 0,因此无论您的游戏逻辑发生什么,我们都会等待完整的 1000 毫秒。

在下一帧中,_previousTicks 将等于 0,_currentTicks 现在将等于大约 1000 毫秒。这意味着 _deltaTicks 将等于 1000。

我们再次点击了 LimitFPS 函数,但这次的 _deltaTicks 为 1000,因此我们等待 0 毫秒。

这种行为会像这样不断地翻转。

wait 1000ms
wait 0ms
wait 1000ms
wait 0ms
...

那些等待 0ms 基本上是你的 FPS 的两倍。

您需要在游戏逻辑的开始和结束时测试时间。

//The timer object.
Timer* _timer = new Timer();

//Start the game loop and continue.
while (true)
{
    //Restart the timer.
    _timer->LoopStart();

    //Game logic omitted

    //Obtain the end time
    _timer->LoopEnd();

    //Now you can calculate the delta based on your start and end times.
    _timer->CaculateDelta();

    //Limit the frames per second.
    _timer->LimitFPS(1);
}

希望有帮助。

于 2013-09-03T14:36:34.510 回答
-1

假设您的游戏循环仅在 SDL_Delay() 过期时触发,编写以下内容还不够:

void Timer::LimitFPS(int targetFps)
{
    SDL_Delay((unsigned)(1000 / targetFps));
}

根据请求的目标 FPS 将您的游戏循环延迟适当的毫秒数?

于 2013-09-03T13:44:42.043 回答