SDL中文教程

_(:3」∠)_目前一团乱还请各位见谅
总之各位随意~

第八节:计时器

| Comments

【本文还没有翻译完毕】

原文地址:http://twinklebeardev.blogspot.com/2012/10/lesson-8-timers.html

In this lesson we’ll add onto our small class library of one (the Window class) by creating a simple timer and then use it in a simple program. To do this we’ll be making use of the SDL_Timer functions, specifically SDL_GetTicks which returns the milliseconds elapsed since SDL was initialized.

本节我们将通过创建一个简单的计时器来添加一个类到我们的小类库中,然后在一个简单的程序中使用它。为了做到这些,我们将充分使用SDL_Timer里的函数,尤其是SDL_GetTicks,它会返回以毫秒为单位的自从SDL初始化之后,经过的时间。

So how would we be able to measure a time if we can only tell how long it’s been since SDL was initialized? Well we could mark down the value of SDL_GetTicks when we start the timer as startTicks and then again when we stop it as endTicks. We can then subtract endTicks - startTicks to get the milliseconds elapsed during the measurement. Seems easy enough right?

所以,如果我们只知道自从SDL初始化到现在经过了多久,我们应该怎样计量时间?我们可以使用stratTicks在开始计时的时候记下时间,然后用endTicks结束。然后我们可以用endTicks减去startTicks来获得其中间隔了多久。简单吧?

Let’s begin planning out how we’d like our Timer to function before we start putting it together. We’ll definitely need functions for starting, stopping and getting the elapsed ticks (measured in milliseconds), and we’ll also want to be able to check if the timer has been started. In addition I think it’d be nice if we could pause and unpause the timer, and maybe a function to restart it that would return the elapsed ticks and start the timer over again all in one go. We’ll also need variables to track the start and pause points as mentioned above in how to use SDL_GetTicks to determine the elapsed time, along with some values to track the state of the timer.

在开始编写之前,我们先计划一下我们所希望的Timer的功能。我们无疑需要开始和停止计时的函数还有获取经过的时间(以毫秒为单位)的函数,我们还需要检查计时是否已经开始的功能。此外,我觉得加上暂停和取消暂停的功能也不错,另外也许还需要有一个可以返回经过的时间并重新开始计数的函数。我们还需要几个用来记录开始和暂停的时间点的变量,以及几个记录计时器状态的变量。

So let’s try something like this:

于是,我们试着写下这些代码:

That looks pretty good, so let’s get started implementing these functions in timer.cpp, beginning with the constructor.

看起来挺好,于是我们就着手在timer.cpp里实现它吧。首先是构造函数。

When we construct a new timer we want it to be off, ie. not started or paused. We can do this like so:

当我们构造一个新计时器的时候,它应该是关闭的,或者应该说是既没有开始也没有暂停。我们可以通过以下方式实现:

In our Start function we’ll want to tag the timer as started and record the value of SDL_GetTicks when Start was called, so that we can properly return the elapsed time, which is the difference between the current SDL_GetTicks and the value of mStartTicks. In our Stop function we simply want to tag the timer as stopped, by setting mStarted and mPaused to false.

在我们的Start函数内,我们需要将计时器标记为started已经开始,并记下开始时SDL_GetTicks中的值,以便于之后能正确地返回经过的时间。而经过的时间就是当前使用SDL_GetTicks获得的时间与mStartTicks的差。在我们的Stop函数中,我们只需要通过把mStarted与mPaused设为false,将计时器标记为停止。

For our Pause and Unpause functions we’ll need to do a bit more work. We wouldn’t want to pause the timer if it wasn’t started or was already paused as both operations don’t really make sense. When we pause the timer we’ll also need to store the elapsed time so that we can preserve the timer’s value so that when we unpause we continue adding on to the measured time instead of resetting it. We can do this with the method discussed above, were we take SDL_GetTicks - mStartTicks as the elapsed time, where mStartTicks is the value of SDL_GetTicks when the timer was started. So Pause should look like this:

暂停和取消暂停的函数还需要一点。如果计时器压根没有开始或者已经暂停了,我们就没必要让它暂停,因为那没有意义。当我们暂停计时的时候,我们还需要将经过的时间保存下来,以便于能恢复计时器经过的时间。这样之后在取消暂停的时候,我们可以继续在这个计时器上计数,而不是重新开始计数。我们可以用前面提到的方法做到这一点。我们用SDL_GetTicks - mStartTicks 作为经过的时间,而mSartTicks是计时器开始的时候用SDL_GetTicks 获得的时间。所以说,Pause函数应该是这样的:

So now mPausedTicks stores the elapsed ticks, so we can resume timing when we call Unpause. In Unpause we’ll want to mark the timer as not paused and use the value of mPausedTicks to set the value of mStartTicks to have some offset from the value of SDL_GetTicks at the time Unpause is called so that we preserve the value of the timer. We can do this by setting mStartTicks to SDL_GetTicks - mPausedTicks, so Unpause also ends up being quite simple:

所以现在,mPausedTicks里保存的是经过的时间,这样我们就可以在调用Unpause函数的时候恢复计时。在Unpause中,我们要把计时器标记为没有暂停,并把mPausedTicks的值赋给mStartTicks

Our function Restart, to restart the timer and return the elapsed time turns out to be quit simple. The function Ticks is used to get the elapsed time, then the timer is restarted and the value is returned. This ordering is very important as we need to get the elapsed time before we reset the timer, or else we’ll return 0 every time.

我们的Restart函数,想要重新开始并返回

Finally we arrive at the most important function of our Timer, the one that actually tells us how much time has elapsed! We’ll only want to return a value if the timer has been started, if the timer is paused we’ll want to return the value of mPausedTicks (the elapsed time between Start and Pause), if the timer is running we’ll want to return return the elapsed time, with SDL_GetTicks - mStartTicks. If it’s not started then we’ll want to return 0, as no time has been measured.

We finish off our timer with some simple getters to check if the Timer is started or paused:

And there we have it! A useful, simple timer. Now let’s try using it in a program to make sure it works. We’ll make a very simple program that will display the elapsed time and read some input for starting/stopping/pausing/unpausing the timer. For this program we’ll also need the Window class that we wrote in Lesson 7 to provide the various graphics functions we’ll need.

I’ll only be posting code relevant to the specifics of using the timer in the lesson, but if you have difficulty with some code that isn’t posted you can always find the full source and assets for each lesson on Github.

After opening our Window we’ll want to create an instance of the Timer class and some SDL_Textures to hold our messages.

Here we also setup the message box positioning to stick a bit below the middle of the window height (recall that y is the y position of the top-left corner) and set its width and height equal to the texture’s width and height.

We also want to display the value of the timer’s Ticks function, the elapsed time, after the end of the “Ticks Elapsed: ” message. There’s one small issue though, Ticks returns an int, but we need a string to render a message with. This can be resolved by using a stringstream; we write Ticks to the stream and then pass it to the message creation function as a string, like so:

We then clear the stringstream by filling it with a blank string and set the positioning of the message to be a bit after the text message.

Within our event polling loop we’ll want to check for some key presses to tell the timer to start/stop/pause/unpause as desired.

Now before we render everything we’ve got one last problem to solve. How are we going to update the texture displaying the number of ticks on the screen? We can do something where we simply destroy the old texture and recreate a new one with the updated Ticks, but we wouldn’t want to do this if the timer is paused or stopped since there’d be no reason to change the message.

Sounds like we’ll just need an if statement, and to copy down the code we used to create the texture initially:

We can put this bit of code in our logic section right after the input polling. Our rendering section will just draw the two SDL_Textures with their Rect’s and we finish off the program as always by destroying our textures, calling Window::Quit and returning.

When you run the program you should see something like this:

Where the timer will start at 0 and begin increasing once you start it. Pausing will cause the timer to stop counting, unpausing will resume it from where it left off. Stopping the timer will stop it, and when restarting it will begin again at 0. Note that the value displayed doesn’t reset when the timer is stopped but rather when it’s resumed.

Lesson 8 Extra Challenge! Make an additional message display to state whether the timer is stopped/paused Hint You’ll need to make another SDL_Texture and use the Timer::Started and Timer::Paused functions to see what the timer’s state is.

End of Lesson 8 Thanks for joining me! I’ll see you again soon in Lesson 9: Playing sounds with SDL_mixer.

Comments