|
||||||||||||||||||
Add Forum to Favorites | Send Topic To a Friend | View Forum FAQ | Track this topic |
Last Thread Next Thread ![]() |
| Frame Rate Independent Movement |
|
![]() BillB Member since: 6/4/2001 |
||||
|
|
||||
| I would put the test before the division: if (speedfactor <= 0) speedfactor = 1; fps = targetfps/speedfactor; prob doesn't matter in this case but since your testing for zero it implies that speedfactor could be zero which would result in a divide by zero error. Round and round and round we spin with feet of lead and wings of tin |
||||
|
||||
![]() BillB Member since: 6/4/2001 |
||||
|
|
||||
| QueryPerformanceCounter(¤tticks); should read: QueryPerformanceCounter(currentticks); <- There should be a ampersand in front of currentticks but I can't get it to display in this message. Round and round and round we spin with feet of lead and wings of tin Edited by - BillB on June 4, 2001 9:35:07 PM |
||||
|
||||
![]() Invhunter Member since: 11/29/2000 From: Frankenberg, Germany |
||||
|
|
||||
| Everyone aware of basic game- and realtime-programming should be able to develop such a class. I hope the flooding is realy over now! BTW good work anyway! I just think there are too much beginners trying to develop some realtime-programmes with a leak of basic knowledge. Perhaps they should first read some books and then trying to program. If they are not able to have any idea how to program such a simple class they should start over to read the book again, and again, and again, and again, . . . . |
||||
|
||||
![]() Anonymous Poster |
|||||
|
|||||
The way I do this is as follows:
in the init function:
each frame:
Now, in my game code, I specify all velocities in units/second, and all accelerations in units/(second^2). So if I want my tank to move at 4 unit per second, I just call:
each frame... War Worlds - A 3D Real-Time Strategy game in development. |
|||||
|
|||||
![]() Sly Member since: 7/28/2000 From: Brisbane, Australia |
||||
|
|
||||
| Three warnings for you all. First of all, never rely on QueryPerformanceCounter() to return a valid value. One machine here in our office responds with an erroneous value about once every four seconds. The value in error is approximately 10,000 times the value received the previous few frames. This was causing major problems with our frame rate system on this one machine. Luckily we caught it before the game's release. Now we use GetTickCount() which has been very reliable. Secondly, always have a backup for QueryPerformanceCounter(). If QueryPerformanceFrequency() returns zero, then there is no high performance counter available in hardware. Therefore you should drop back to using GetTickCount(). And lastly, another developer here warned us that one of his machines at home returns an incorrect value for QueryPerformanceFrequency(). The value returned is of a magnitude 10 times lower than it should be. Steve 'Sly' Williams Code Monkey Krome Studios Edited by - Sly on June 5, 2001 7:14:23 PM |
||||
|
||||
![]() Gherkin Member since: 5/20/2001 |
||||
|
|
||||
| I wonder if Quake3 or UT runs perfectly on those systems you talk about there. GetTickCount is way slower than Query... (correct me if im wrong, havent tested it myself) Pascal vd Heiden XODE Multimedia Programmers are artists. |
||||
|
||||
![]() Dean Harding Member since: 2/28/2001 From: Sydney, Australia |
||||
|
|
||||
quote: Yeah, I have a test for the first QueryPerformanceFrequency(), which if it fails, I use timeGetTime() elsewhere. I didn't include it for clarity's sake. (BTW, I was the Anon Poster...) I haven't heard about those other two problems. I suppose a solution to the first one is to test your return value compared to the last and if the difference is too big to get another value. Does the problem still show up if you can QueryPerformanceCounter() twice in succession? I don't know what to do about the other one. Maybe let the user specifiy the frequency in some way if their machine returns the wrong value? I guess if that's the case though, a lot of games won't run properly since so many rely on QueryPerformanceCounter. War Worlds - A 3D Real-Time Strategy game in development. |
||||
|
||||
![]() TrIaD Member since: 10/30/2000 From: USA |
||||
|
|
||||
| Random Comments This is really mean, but... I think QueryPerformanceCounter should work on any newer system... so you could make your "minimum system requirements" require a PC that has a performance counter... I think it's anything 586 (Pentium 1) or later, and any 586-compatible... ...but then I've never programmed on an AMD, either (yuck!) Basically, any method of getting the "time" OTHER than the high-performance counter will have horrible accuracy... possibly as bad as 20-200 ms (!) resolution... To display an ampersand, use & --Tr][aD-- |
||||
|
||||
![]() Sly Member since: 7/28/2000 From: Brisbane, Australia |
||||
|
|
||||
quote:There is a KnowledgeBase article about this problem. It is a hardware problem with certain chipsets. The article also has code to detect these leaps in returned values. quote:The user will not know what the frequency is supposed to be. This is a problem with some hardware that is noted in this Knowledge Base article, but I do not think that this developer has a Japanese version of Win98 on a NEC PC9800. I don't think that this is a problem to worry about. Steve 'Sly' Williams Code Monkey Krome Studios |
||||
|
||||
![]() CPlasmaGuns Member since: 12/15/2000 From: USA |
||||
|
|
||||
| This article doesn't address problems when collision detection fails because something moved too far in one frame. I prefer to use frame skip, where the graphics are drawn for a frame only when the frame rate is at the target. Otherwise, only game logic happens until the game has time to draw the graphics. |
||||
|
||||
![]() DeltaVee Member since: 6/14/2000 From: Ponte Vedra Beach, USA |
||||
|
|
||||
| BTW, for collision detection, use vector intersection. That tells you if and where a collision occurs. So it doesn't matter what your frame rate is. I personally don't use QueryPerformanceFrequency(), as it can fail. I stick to timeGetTime(). After all, I lock the frame rate so that it never exceeds the screen refresh. So at 65Hz that gives me approx 15 msecs (or ticks) per frame. Since I am not simulating nuclear rections this precision is good enough for me. D.V. |
||||
|
||||
![]() stefu Member since: 4/22/2001 From: FIN |
||||
|
|
||||
| I have currently slightly different system to have constant movement. MoveFrame(float seconds) { // Move objects in at speed 100 fps while( seconds>0.01f ) { object_list->Move(0.01f); seconds -= 0.01f; } objectlist->Move(seconds); } What do you thin about this? If machine is slow, then this is not good, if Object::Move has much calculations. But this keeps objects on same line on slow and fast machines. |
||||
|
||||
![]() Catfish Member since: 9/22/2000 |
||||
|
|
||||
| While this is fine for any demo or single player game, it's worth a look at fixed timesteps for a performance boost & the ability to make things deterministic - vital for multiplayer. The idea is to have your game physics update at a constant rate - say 25 times a second. Frames are drawn as fast as possible in between those physics ticks, using interpolation to smooth things out. I tried this in a simple particle engine I'm using, and got a 50% performance boost, simply because I'm not doing my physics calculations every single frame. There is a very long forum thread over at flipcode that I would point you to if you're interested: Main loop with fixed timesteps Catfish Edited by - Catfish on June 7, 2001 8:33:23 PM |
||||
|
||||
![]() LoreKeeper Member since: 6/11/2000 From: Stellenbosch, South Africa |
||||
|
|
||||
| Well, I've not worried much about constant game-rates (yet) - but it seems to be one of those things that come approaching on the horizon. I've got a few suggestions that should fix up a few issues, particularly with very high fps-rates, and may actually reduce visual jerkiness (on the sub-detectable level): Without too serious visual artefacts it should be possible to use GetTickCount every 5th or 10th frame. Considering the high fps games achieve nowadays that should not yield visual jerkiness, whilst putting several frames between GetTickCount increases the effective resolution and thus accuracy that GetTickCount can deliver (and correspondingly makes the "SpeedFactor" calculation considerably more accurate as well. Obviously the same "SpeedFactor" will then be used over 5,10,whatever frames. I've played around with GetTickCount to get a good measure of my frame-rate, and discovered that GetTickCount is called frequently enough to return values of about 20 or below, then the resultant fps (or SpeedFactor, etc) calculation yields very granular or inaccurate results. Henri aka A-Lore |
||||
|
||||
![]() Anonymous Poster |
||||
|
||||
| On Intel-based platforms, you can get a finer resolution than QueryPerformanceCounter by counting clock cycles with the following code: void ReadTimeStampCounter(__int64 *apCounter) { asm { push edx rdtsc push edi mov edi, dword ptr apCounter mov dword ptr [edi], eax // Low 32-bits of the TSC mov dword ptr [edi+4], edx // High 32-bits of the TSC pop edi pop edx } } Then, call the function using the address of a 64-bit integer. Note that the above code doesn't test to see if the processor supports the rdtsc instruction at ring-3. Most/all Pentium chipsets have support for this...but the OS is a bigger concern since it may have cleared the CR4 register bit to disable the rdtsc instruction. To use this as a time-based function, calculate how many clock cycles per second it takes (the equivalent function to QueryPerformanceFrequency). |
||||
|
||||
![]() Anonymous Poster |
||||
|
||||
| In my experience, the "distance = velocity*time" method works well if yu have a frame rate that isn't "too high" or "too low". At too high of a frame rate you will run into rounding issues (note I'm talking about VERY high rates). At too low of a frame rate your simulation becomes inaccurate. Imagine a ball flying in an arc. If your update rate is very low you may get something more like a triangle shaped path (update at the start, top, and end of the arc). The previously mentioned constant frame rate method seems to be the best way to approach things. All you do is calculate how many FRAME_LENGTH boundaries you have crossed since the last update and update your world that many times (passing in FRAME_LENGTH as the length of the last frame). I have applied this method in very low frame rate systems and acheived playability at rates as low as 700ms per frame. As a side note, there are even more frustrating issues that arise when using the high performance counter. Many systems have a unique high performance counter on every CPU. Windows seems to have no remorse when tossing your thread around from CPU to CPU. When you get moved, your counter will not be the same counter and it is certainly possible to get very large or possibly even negative time deltas. You always double check any time delta you get from a hardware counter and do something smart (use the last delta...throw it out...shrug) if it looks suspicious. |
||||
|
||||
![]() vajuras Member since: 3/9/2004 From: Los angeles, CA, United States |
||||
|
|
||||
| I already had a frame counter in my engine so I used that instead of the example code. Since my engine already knows the current fps all I had to do was plug that number in: Vector final_position = m_pos + vel * ((target fps) / current fps); The goal is that if you're already running at 60 fps, target fps/current fps will give you 1.0f meaning that since you're already at the cap, there's no need to mess with the motion further. |
||||
|
||||
All times are ET (US)![]() |
Last Thread Next Thread ![]() |
|