FPS口吃 - 游戏以双FPS指定运行?

时间:2013-09-03 13:23:37

标签: c++ visual-studio-2012 sdl frame-rate

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

我遇到的问题是游戏循环的数量是我预期的两倍。例如,如果我尝试将帧数限制为1 FPS,那么将在1秒内传递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;此代码已被省略。

2 个答案:

答案 0 :(得分: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现在将等于大约1000ms。这意味着_deltaTicks将等于1000。

我们再次点击LimitFPS函数,但这次使用_deltaTicks为1000,这样我们等待0ms。

此行为将不断翻转。

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);
}

希望有所帮助。

答案 1 :(得分:-1)

假设只有在SDL_Delay()过期时才会触发游戏循环,这不足以写:

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

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