Archived

This topic is now archived and is closed to further replies.

max621

Frame-independant-rendering... (timers)

Recommended Posts

Ok what I want to do is to have my game/program run independant of the speed the computer can render the scene. Like all games do . Heres some pseudo code of what I want to do: onTimeTick() { Input(); Update(); AI(); Render(); }; So now what do I do to get that onTimeTick?? I hope you understand what I mean.. Thanks.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
I think that making the CPU wait until the clock ticks is the wrong way to do this. What you probably should do is measure how long it took the last frame to draw, and adjust the timescale of your game so that each frame draws a smaller slice of time, if you know what I mean. So if your cpu is twice as fast, the characters move half as much in each frame, because you are drawing twice as many frames every second. Otherwise, you force every computer down to the lowest standard.
-FallingFrog

Share this post


Link to post
Share on other sites
What I just want to do is that so the game will run at a constant speed no matter how crappy your computer is.. like instead of doing the physics everytime the frame is done rendering, the physics are done, and the rendering just keeps on coming, even if the old one isnt done yet... understand?!
Just like what quake or tribes or UT or half-life do..independant of frames..

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
What I do in my programs(this is straight from the sams directx7 book) is I use a timer to check if it is time to update. I make it so I set the timers speed. Ie. most of my apps have the graphics part going at 60fps and input polling at 200 times per second. The wat I do this is with the frequency counter:
QueryPerformanceFrequency() used to get the frequency of the counter
QueryPerformanceCounter() get the current count(arbitrary value)

Go on to the msdn and look these 2 up....there basically all u need.

If you can''t figure out how to implement them, email me at:
blide@mail.com

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
I also forgot to mention that this method works independent of the speed of your comp...because if its been 1/60th of a second(or whatever i set my counter to) it automatically updates regardless of if the previous time has finished. The frequency counter is a hardware counter that is extremely accurate!!! As you read earlier I use it for input also...I use direct input to poll the mouse and keyboard, and my comp is so fast I had to put a counter and only check 200 times a second....cause my comp was doing it like a 1000 times...so when I incremented positions, everything was moving around to fast on my comp..and slower on other comps. This way even input is the same so I can have one set of values that I increment by each time I poll and see if a key is pressed.

-blide
blide@mail.com

Share this post


Link to post
Share on other sites
What u want is 2 threads in the app.

The first thread (created automatically by the app) will take care of the message que and graphic rendering.
This is how i do it..

int PASCAL Winmain(....)
{

init code...
...
...

while( 1 )
{
if( PeekMessage(....)
{
GetMessage(..)
TranslateMessage(..)
DispatchMessage(..)
}
else if(bAppIsActive)
{

BlitFrame();

}
else
{
WaitMessage();
}


}



The second thread u have to create using "timeSetEvent" and have it call a function you supply, something like "TimerUpdate()".

Your TimerUpdate() function will be called xx times a second
to update the gameplay, such as sprite movement.


This is how some games work, including mine, although some work by adjusting the gameplay by each frame. (both do the same thing)

This way u are keeping the gameplay at a steady rate, whilst using as much graphical fire power as possible. If u are worried about the graphics taking too much juice, u can use the DirectDraw command..
WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN,NULL);
to limit the FPS to 60 or 75, leaving enough juice for the gameplay update and other programs.






I guess u can do it your way and use WaitForVerticalBlank to control the speed, but the Vertical blank runs at 60, 75, or even 100 on really good monitors/videocards and laptop LCD''s.
I think there is a way to limit the vertical wait to 60FPS..refer to the DX docs.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
You could do something like this.

===========================================
LONGLONG freq = 0;
LONGLONG lasttime = 0;
LONGLONG frametime = 0;
// setup the frequency and the start time.
QueryPerformanceFrequency(&freq);
QueryPerformanceCounter(&lasttime);

// game loop thingy
while(!exitapp) {
QueryPerformanceCounter(&thistime);
// calculate the number of seconds since the last frame
float seconds_elapsed = (thistime - lasttime) / freq;
lasttime = thistime;
// move stuff, do AI etc.
doframe(seconds_elapsed);
}
============================================

The seconds_elapsed variable will be probably be some small number like ''0.0234''. Each of your moving objects has a speed such as 100 pixels per second. When you do its movement you multiple the speed by the seconds_elapsed variable and move it by that much. e.g.

move_dist = speed * seconds_elapsed;
2.34 = 100 * 0.0234

So for a object with a speed of 100 where 0.0234 seconds passed since the last frame, the object would move 2.34 pixels.

This means that what ever speed the computer is the game will run the same, it will just be smoother on faster computers.

Some older processors don''t have performance counters but every one from Pentium onwards does so it wont really matter.

Share this post


Link to post
Share on other sites
Hey, Anonymous, I ''m using GetTickCount instead of the performance counter functions... is there a really good reason to use them? I don''t think you need so much precision and accuracy. After all, GetTickCount deals with msecs, not secs, so this should be enough for your game''s main loop...

VBMaster

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
On Win9x the minimum resolution for GetTickCount() is 55ms. On WinNT and 2000 it is a bit better at about 10-15ms. So it isn''t always correct.

QueryPerformanceCounter() is always accurate to whatever the frequency is because the hardware timer is queried every time it is called. The call can take a bit longer than GetTickCount() but not enough to bother with since it is only called once per frame.

It probably dosn''t matter for most things though. I''ve just got used to using QueryPerformanceCounter().

Share this post


Link to post
Share on other sites
Pricipally: yes. Practically: No.

Though the returnvalue of GetTickCount is in milliseconds, the accuracy of that timer is far less.

I don''t know the exact values for this, but I have read somewhere that the accuracy in Windows NT is only 55 ms. Also, in some other post regarding this subject, somebody mentioned a difference in time between two adjacent GetTickCount() calls of 100 ms or more.

This doesn''t mean the GetTickCount() timer cannot be used for a game, it only means that if your game needs smooth-scrolling and the game should work on a variety of computers, you probably want to use the performancecounter.

Share this post


Link to post
Share on other sites
Here is how I do mine...

        
bool notDone = TRUE;
while(notDone)
{
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)
{
if(msg.message == WM_QUIT)
notDone = FALSE;

TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
if(gtimer.istime()) //gtimer is for graphics

{ //update frames here

}
if(itimer.istime()) //itimer is for input

{ //poll keyboard and mouse

}
}
[/source]

By the way...my timers are using QueryPerformanceCounter...this seems to work very well for me.
So how I use the performance timer is something like:
[source]
QueryPerformanceFrequency(cps); //i dont remember if it returns

//or uses argument

ctime = cps / fps; //fps is whatever frames per second you want

QueryPerformanceCounter(lasttime);

//that WAS the init

//here IS the istime()
bool istime()
{
QueryPerformanceCounter(currenttime);
if(pasttime + ctime >= currenttime)
return TRUE;
else
return FALSE;
}


Edited by - blide on July 20, 2000 2:45:06 AM

Share this post


Link to post
Share on other sites