Advertisement

04.06 - It's About Time...

Started by May 29, 2001 09:46 AM
26 comments, last by Teej 23 years, 1 month ago
Hi Teej,
I was just wondering why you chose to use GetTickCount() instead of timeGetTime(). I checked MSDN and it seems GetTickCount() is only accurate to 55ms. timeGetTime() is accurate to 1ms in Win95 and 5ms in Win2k.
Sir Melvalot: Good question. I spent a good half-hour reading through all of the time-related API functions with resolutions in the msec. range, and I left still not totally sure on which is the best. I''m looking at the online help again, and I guess that I passed up timeGetTime() because of the machine dependance (NT/2K vs. 9X) and the need to use timeBeginPeriod() and timeEndPeriod(). Now that I''m thinking about it again, I''m beginning to agree with you, especially if the resolution of GetTickCount() is in fact that bad (I didn''t see that information when I was looking).

In other words, your suggestion is quite justified, and I''ll have to make the changes to the article. For those of you reading this later on, I''ll explain the change:

The first version of this article (before June 1/2001) used the GetTickCount() function to get the number of milliseconds elapsed since the system was started as the preferred method. There''s more than one method of getting elapsed time in milliseconds, but originally I chose to stick with GetTickCount().

As of June 1st, the article has been updated to use timeGetTime(), which seems to be the superior method of timing intervals at high resoltions.

Thanks for the heads-up on the shortcomings of GetTickCount()!

Teej
Advertisement
Why not just check to see if the system has a high resolution timer (QueryPerformanceFrequency() will return 0 if it doesn''t), and if it does, use the high-resolution one, and if it doesn''t use the multimedia timer (timeGetTime()). That''s how I do it. Except with the high-resolution timer you have to check how many ticks per second it does so you can accuratly determine the time on it.
Anon: Well, I''m always open to better methods. After all, that''s the reason we''re all here (me included). If we put our heads together when designing games, we''ll truly go far.

I''ve looked (again) at the timer functions available, and like you''ve mentioned, there may not necessarily be a high-performance timer on the machine... I figure that if we''re getting 1/1000th of a second (1 msec.) resolution from timeGetTime(), isn''t that already ideal?

Teej
Hi everyone,

I have two questions...
First of all, I have made a background by blitting 32x32 tiles to the screen, and then blitting an arrow picture instead of that flying 'A'. The first few seconds the program seems to be very slow and the arrow moves in shocks. After a few seconds the arrow flies at a steady pace. Is this normal?
The second problem is, that this is the first source file from Teej that gave me a warning:
GameMain.cpp(118) : warning C4018: '>=' : signed/unsigned mismatch
Line 118 is: while (spriteTickCount >= (1000 / spriteRate))
Is this a problem? Everything seems to compile alright, but just wanted to be sure.

Everything else seems to be going fine thus far... Really enjoying the forum!

Edited by - Joris Slob on June 12, 2001 10:11:16 AM
Joris Slob: The studdering you''re seeing is normal, and has to do with the framerate being volatile as the program is starting. I admit, it''s ugly, but it''s something that can be avoided with an intro screen or other such pause.

As for your signed/unsigned question, yes, that too is normal. You see, a DWORD value is taken to be unsigned, and an int is a signed value. Here, the compiler is just pointing out the fact that in certain circumstances the two aren''t compatible. Of course, we know better -- our int will always be positive. If you want to make the compiler happy, you can either change the variable to something like unsigned int, or cast it right where it''s being used like so:

while ((int)spriteTickCount >= (1000 / spriteRate))

OR

while (spriteTickCount >= (DWORD)(1000 / spriteRate))

...whichever.

Teej

Advertisement
Hi,

can anybody tell me where I can find more info on the WORD, DWORD and BYTE data types?

Are they DX specific types or what?
thanks
Ð!@ßأܧ
Diabolus,
No those aren't DX specific types, they are part of the windows SDK. If you take a look at the 'windef.h' file in your VC++ include directory you'll find all the type defintions. In fact you could define them yourself if for some reason you felt the need to do so.

DWORD, WORD and BYTE are defined as follows:
typedef unsigned long DWORD
typedef unsigned short WORD
typedef unsigned char BYTE

Hope this helps

Edited by - Dionysis on June 13, 2001 4:16:34 PM
Here you go. Now you can try to shoot the letter A with a letter A.

if (KEYDOWN(DIK_SPACE))
{//shoot a letter up

G.bIsFiring = TRUE;

}


while (spriteTickCount >= (1000 / spriteRate))
{
// Move the sprite one pixel over
pos++;

if (G.bIsFiring)
{
// Move another sprite one pixel up
bulletpos--;

if (bulletpos <= 0)
{
G.bIsFiring = FALSE;
bulletpos = SCREEN_HEIGHT;
}
}

// Wraparound the display if off the right edge
if (pos > SCREEN_WIDTH)
pos = -SPRITE_WIDTH;

// Update the sprite''s movement counter
spriteTickCount -= (1000 / spriteRate);
}

// Rendering


EraseBackground();

// Draw the sprite
rectSrc.left = rectSrc.top = 0;
rectSrc.right = SPRITE_WIDTH - 1;
rectSrc.bottom = SPRITE_HEIGHT - 1;

rectDest.left = pos;
rectDest.top = 0;
rectDest.right = rectDest.left + SPRITE_WIDTH - 1;
rectDest.bottom = rectDest.top + SPRITE_HEIGHT - 1;
G.lpDDSBack->Blt(&rectDest, G.lpDDSRes, &rectSrc, DDBLT_WAIT, NULL);

if (G.bIsFiring)
//draw the other sprite
{
rectSrc.left = rectSrc.top = 0;
rectSrc.right = SPRITE_WIDTH - 1;
rectSrc.bottom = SPRITE_HEIGHT - 1;

rectDest.left = SCREEN_WIDTH/2;
rectDest.top = bulletpos;
rectDest.right = rectDest.left + SPRITE_WIDTH - 1;
rectDest.bottom = bulletpos + (SPRITE_HEIGHT-1);
G.lpDDSBack->Blt(&rectDest, G.lpDDSRes, &rectSrc, DDBLT_WAIT, NULL);
}
EZ

For those of us who are apprehensive about using floating points in our code (yeah yeah yeah, I know modern FPU/CPU are fast) anyway I am using a fixed point solution (IMO fixed point is more suitable to 2D game, I''d use floating point in a 3D game however).

We all know 1000 milliseconds = 1 second. 1000 is almost 1024, which is 2^10. I smell an optimization.

Pseudocode:

  game_play(int deltatime)  // game_main calls this and passes my time delta{    // physics logic    for(each object)    {        object[i].pos.x += object[i].vel.x*deltatime;        object[i].pos.y += object[i].vel.y*deltatime;        // etc //    }           // blitting    for(each object)    {        blit each object at object[i].pos.x>>10, objecti[i].pos.y>>10    }    }  


See what I do is assume the time delta is a 22.10 fixed point number.

This works because my object''s positions are also in 22.10 fixed format. When I go to render the objects, I right shift their positions by >>10 to get the whole portion, and this is where I blit them. What''s cool is that internally, I get 1/1024 subpixel precision, without using floating point. Velocities are just regular integers at the moment, where 1 = 1 pixel per second.

In reality you can setup positions, velocities and the time delta as fixed point numbers, with any number of fractional bits you want, just ensure you don''t lose too much precision due to right shifting, and don''t overflow when multiplying. I am actually going to give my velocities 6 bits of fractional precision, I''ll just have to right shift my positions by >>16 when blitting, to compensate for it.

It works.

This topic is closed to new replies.

Advertisement