Skip to main content
gamedev.net
🔒 Locked

Timers

Started by cptrnet Apr 10, 2006 at 3:07 PM 9 replies 900+ views
Original Post
cptrnet
cptrnet
Hi gamedev, I haven't been around in a while and I am getting motivated to pick up my old game and start working on it again. I haven't worked on it in about 6 months and I am very condfused about what I am doing. It is programmed in c++, win32, gdi. I have a Timer class that uses a thread and every interval it calls a function that I give it.

DWORD UTimer::Run(LPVOID)
{
	while(m_bIsRunning)
	{
		m_TimeEnd = timeGetTime() - m_TimeStart;
		m_Time += m_TimeEnd - m_TimeStart;
		m_TempInterval += m_TimeEnd - m_TimeStart;
		m_TimeStart = m_TimeEnd;  
		if(m_TempInterval >= interval)
		{
			m_TempInterval = 0;
			timer_func(m_pData);
		}
		m_TimeLeft = interval - m_TempInterval;
		Sleep(20);
	}
	return GetLastError();
}


It seems like it calls the function ok but I want to know how many milliseconds or seconds are left until it calls the function. I added the line m_TimeLeft = interval - m_TempInterval; above the sleep function in order to accomplish this but it gives my unexpected results. The m_TempInterval variables sometimes comes up with negative numbers that throws the calculation off by a ton. I am thinking it has something to do with the timeGetTime() or something. Anyway sometimes it works and comes out with the correct number and it seems to have the timing down perfect, but the m_TimeLeft variable comes up with what I don't want. Has anyone else tried this? Any help would greatly be appreciated. Thanks.
If you insist on saying "DUH", try to make a post that makes a little more sense
cptrnet
cptrnet
It probably is more effort than it is. What I am trying to do is to have an effect in my game sort of like a power up that lasts for so long. On the screen it will have a display saying how many seconds are left on the power up. I am not sure how to achieve this as I don't know all what I really need to do. I just took the idea behind a Timer object in VB and said why don't I give that a try. I guess I could just put the time code in the main loop. Then do that QueryPerformaceCounter thing.
If you insist on saying "DUH", try to make a post that makes a little more sense
aviosity
aviosity
Here's how I implemented timers.

//HEADER FILEclass Win32Timer {private:	__int64		startTime;		//Time that timer started at	__int64		rate;			//Frequency clock operates at	GLdouble	rateInverse;	        //Calculate the rate inverse for speed, to multiply instead of divide	public:			Win32Timer		(GLvoid);	GLint		initTimer		(GLvoid);	GLint		resetTimer		(GLvoid);	GLdouble	getElapsedTimeSeconds	(GLvoid);};//_______________________________//CPP FILEWin32Timer::Win32Timer			(GLvoid){	initTimer();}GLint		Win32Timer::initTimer				(GLvoid){	if(!QueryPerformanceFrequency((LARGE_INTEGER*) &rate))		return -1;	if(!rate)													return -1;	rateInverse = (GLdouble)(1.0/(GLdouble)rate);	if(!QueryPerformanceCounter((LARGE_INTEGER*)&startTime))	return -1;	return 1;}GLint		Win32Timer::resetTimer			(GLvoid){	if(!initTimer())	return -1;	else				return 1;}GLdouble	Win32Timer::getElapsedTimeSeconds	(GLvoid){	__int64 endTime;	GLdouble retval;	QueryPerformanceCounter((LARGE_INTEGER*) &endTime);	retval = (GLdouble)((GLdouble)(endTime - startTime)*rateInverse);	return retval;}


Now, to implement powerups, you create a powerup class with a member variable for the seconds it lasts. This powerup will also have a timer as a member variable; when a powerup is picked up, reset the timer, get the elapsed time in seconds, and either 1)subtract the elapsed seconds from the time remaining or 2) when the elapsed time modulus 1 is 0 (to be accurate, probably elapsed time modulus 1 equaling between, say, 0.990 and 1.001 [only example]) subtract 1 from the time remaining.

Note that this is a rough throw-together for a small game, and there could be many member functions added to make it more usable. I also realize that creating a timer for each powerup is probably a terribly inefficient design; it would probably be better to add a member function in the timer to get current time that could be recorded as a member variable in the powerup class and add to that the amount of time the powerup lasts to determine endtime, and keep a single timer as a static to be shared amongst all the powerup classes.

Hope that helps,
Aviosity

PS - this is based off of some code in an article on gamedev(I believe)...if I find it I'll post a link.
JohnBolton
JohnBolton
Here are a few things to consider.
  1. By default, the time returned by timeGetTime() is not updated every millisecond. On my system it updates only every 16 or 17 milliseconds. If that is a problem, use QPC (as demonstrated by aviosity).
  2. Sleep( x ) waits for at least x milliseconds, so your intervals will be close to 20 ms but usually longer.
  3. It looks like some of the logic is broken.
Take a look at these changes to your code.
    DWORD UTimer::Run(LPVOID)    {        while(m_bIsRunning)        {            m_Time = timeGetTime();            while ( int( m_Time - m_TimeStart ) >= interval )            {                timer_func(m_pData);                m_TimeStart += interval;            }            m_TimeLeft = interval - ( m_Time - m_TimeStart );            Sleep(20);        }        return GetLastError();    } 
John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!
Adam Hamilton
Adam Hamilton
I have always wondered if using Sleep is worth it... I used Sleep(0) because passing 0 means that the thread is giving up it's remaining CPU time whereas passing a number other than 0 will do above plus wait for that amount of time but it is interesting to note that I once passed Sleep(1) in an empty game loop thinking it would wait around 1-2ms however, I noticed the frame rate drop from 798fps right down to 58fps so I figured it must have been waiting a little longer than 1-2ms

I am considering dropping Sleep(0) from anything I ever create - I believe when your writing a game you want every available CPU cycle you can get you hands on.
cptrnet
cptrnet
Thanks for the help I appreciate it. That was exactly what I needed.
If you insist on saying "DUH", try to make a post that makes a little more sense
JohnBolton
JohnBolton
Also, since your code is running in a separate thread, you need to use thread synchronization functions (mutexs, semaphores, etc.) to prevent one thread from accessing a value in the middle of being changed by another thread.
John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!
Extrarius
Extrarius
Quote:
Original post by Adam Hamilton
[...]I am considering dropping Sleep(0) from anything I ever create - I believe when your writing a game you want every available CPU cycle you can get you hands on.
SwitchToThread is better than Sleep(0) since it's designed for that purpose. Also, most games do not need all the CPU, as long as they get a good share. A person running a top of the line system shouldn't be penalized for it - if all your game does is go from 200 frames per second to 1000, you really shouldn't be hogging the CPU since it's highly unlikely that the player has a display capable of displaying even 200 frames per second.

As far as the OP, why not use SetTimer (or timeSetEvent if you really care about precision) and let windows call your function every ~20ms instead of doing it yourself? At the very least, use CreateWaitableTimer to wait for the time to change.
"Walk not the trodden path, for it has borne it's burden." -John, Flying Monk
cptrnet
cptrnet
SetTimer calls a windows message doesn't it. I have multiple timers that I am keeping. If I put them all in the message handler it will call them all and I don't want that, unless thats not the way how it works.
If you insist on saying "DUH", try to make a post that makes a little more sense
Adam Hamilton
Adam Hamilton
You could always sacrifice fps for more physics calculations for example.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.