高级定时器
现在我们已经做了一个用SDL做的基本计时器,是时候做一个可以启动/停止/暂停的计时器了。
//The application time based timer
class LTimer
{
public:
//Initializes variables
LTimer();
//各种时钟操作
void start();
void stop();
void pause();
void unpause();
//获取定时器的时间
Uint32 getTicks();
//检查定时器的状态
bool isStarted();
bool isPaused();
private:
//定时器开始时的时间
Uint32 mStartTicks;
//定时器暂停时的时间
Uint32 mPausedTicks;
//定时器状态
bool mPaused;
bool mStarted;
};
对于这些新功能,我们将创建一个定时器类。 它具有启动/停止/暂停/取消暂停计时器并检查其状态的所有基本功能。在数据成员方面,我们有像之前一样的开始时间,有一个变量来存储暂停时的时间,还有状态标志来跟踪定时器是在运行还是暂停。
LTimer::LTimer()
{
//Initialize the variables
mStartTicks = 0;
mPausedTicks = 0;
mPaused = false;
mStarted = false;
}
我们的构造函数初始化内部数据成员。
void LTimer::start()
{
//Start the timer
mStarted = true;
//Unpause the timer
mPaused = false;
//Get the current clock time
mStartTicks = SDL_GetTicks();
mPausedTicks = 0;
}
start函数设置启动和暂停标志,获取定时器的启动时间,并将暂停时间初始化为0,对于这个定时器,如果我们想重新启动它,只需再次调用start即可。由于我们可以在定时器暂停和/或运行的情况下启动它,所以我们应该确保清除暂停的数据。
void LTimer::stop()
{
//Stop the timer
mStarted = false;
//Unpause the timer
mPaused = false;
//Clear tick variables
mStartTicks = 0;
mPausedTicks = 0;
}
stop函数基本上重新初始化了所有的变量。
void LTimer::pause()
{
//If the timer is running and isn't already paused
if( mStarted && !mPaused )
{
//Pause the timer
mPaused = true;
//Calculate the paused ticks
mPausedTicks = SDL_GetTicks() - mStartTicks;
mStartTicks = 0;
}
}
暂停时,我们要检查定时器是否在运行,因为暂停一个没有启动的定时器是没有意义的。如果定时器正在运行,我们设置暂停标志,将定时器暂停的时间存储在mPausedTicks中,并重新设置启动时间。
void LTimer::unpause()
{
//If the timer is running and paused
if( mStarted && mPaused )
{
//Unpause the timer
mPaused = false;
//Reset the starting ticks
mStartTicks = SDL_GetTicks() - mPausedTicks;
//Reset the paused ticks
mPausedTicks = 0;
}
}
因此,当我们取消暂停定时器时,要确保定时器正在运行和暂停,因为我们不能取消一个停止或运行的定时器。我们将暂停标志设置为false,并设置新的启动时间。
比如说,如果你在SDL_GetTicks()
报告5000毫秒时启动定时器,然后在10000毫秒时暂停。这意味着暂停时的相对时间是5000ms。如果我们要在SDL_GetTicks
为20000时取消暂停,则新的开始时间将为20000-5000ms或15000ms。 这样,相对时间仍将与当前SDL_GetTicks
时间相距5000ms。
Uint32 LTimer::getTicks()
{
//The actual timer time
Uint32 time = 0;
//If the timer is running
if( mStarted )
{
//If the timer is paused
if( mPaused )
{
//Return the number of ticks when the timer was paused
time = mPausedTicks;
}
else
{
//Return the current time minus the start time
time = SDL_GetTicks() - mStartTicks;
}
}
return time;
}
获取时间是有点棘手的,因为我们的定时器可以运行、暂停或停止。如果定时器是停止的,我们只是返回初始的0值。如果定时器暂停,我们返回暂停时存储的时间。如果定时器正在运行而不是暂停,我们返回相对于它开始时的时间。
bool LTimer::isStarted()
{
//Timer is running and paused or unpaused
return mStarted;
}
bool LTimer::isPaused()
{
//Timer is running and paused
return mPaused && mStarted;
}
在这里,我们有一些访问函数来检查定时器的状态。
//Main loop flag
bool quit = false;
//Event handler
SDL_Event e;
//Set text color as black
SDL_Color textColor = { 0, 0, 0, 255 };
//The application timer
LTimer timer;
//In memory text stream
std::stringstream timeText;
在进入主循环之前,我们声明一个定时器对象和一个字符串流来将时间值变成文本。
else if( e.type == SDL_KEYDOWN )
{
//Start/stop
if( e.key.keysym.sym == SDLK_s )
{
if( timer.isStarted() )
{
timer.stop();
}
else
{
timer.start();
}
}
//Pause/unpause
else if( e.key.keysym.sym == SDLK_p )
{
if( timer.isPaused() )
{
timer.unpause();
}
else
{
timer.pause();
}
}
}
当我们按s键时,我们检查定时器是否启动。如果启动了,我们就停止它。如果没有,我们就启动它。当我们按p键时,我们检查定时器是否暂停。如果是,我们就取消暂停。否则,我们将暂停它。
//Set text to be rendered
timeText.str( "" );
timeText << "Seconds since start time " << ( timer.getTicks() / 1000.f ) ;
//Render text
if( !gTimeTextTexture.loadFromRenderedText( timeText.str().c_str(), textColor ) )
{
printf( "Unable to render time texture!\n" );
}
//Clear screen
SDL_SetRenderDrawColor( gRenderer, 0xFF, 0xFF, 0xFF, 0xFF );
SDL_RenderClear( gRenderer );
//Render textures
gStartPromptTexture.render( ( SCREEN_WIDTH - gStartPromptTexture.getWidth() ) / 2, 0 );
gPausePromptTexture.render( ( SCREEN_WIDTH - gPausePromptTexture.getWidth() ) / 2, gStartPromptTexture.getHeight() );
gTimeTextTexture.render( ( SCREEN_WIDTH - gTimeTextTexture.getWidth() ) / 2, ( SCREEN_HEIGHT - gTimeTextTexture.getHeight() ) / 2 );
//Update screen
SDL_RenderPresent( gRenderer );
在渲染之前,我们将当前时间写入一个字符串流。我们之所以将其除以1000,是因为我们要的是秒,而每秒有1000毫秒。
之后我们将文字渲染成纹理,最后将所有的纹理绘制到屏幕上。
在 这里下载本教程的媒体和源代码。
关注我的公众号:编程之路从0到1