SDL编程入门(23)高级定时器

本文介绍了一个使用SDL实现的高级定时器类,该类支持启动、停止、暂停和取消暂停等功能。通过实例演示了如何在主循环中控制定时器的状态。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

高级定时器

现在我们已经做了一个用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
编程之路从0到1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值