SysRq2000 Posted August 11, 2003 Posted August 11, 2003 Hi. I'm currently developing a 2d game using Direct3D. But I would like to limit my "game loop" to executing just 30 times per second, or said in an other way, I would like my game to run at 30 FPS... What is the best and/or normal way to do this? Currently my game loop is just a plain "Do" loop. I've tried to just use the tick event of a Timer but it is VERY inaccurate. Any suggestions? - SysRq Quote
wyrd Posted August 11, 2003 Posted August 11, 2003 You can limit it by doing something like this; const int MaxFPS = 40; int ticks = 0; int speed = 0; while (true) { ticks = Environment.TickCount; if (ticks > speed) { speed = 1000 / MaxFPS + ticks; // Perform regular game functionality. } } You'll want to do about 10 FPS over what you want for max. The loops always tends to go a bit slower then what's calculated. Quote Gamer extraordinaire. Programmer wannabe.
SysRq2000 Posted August 11, 2003 Author Posted August 11, 2003 Close but no cigar... Thx for the suggestion. However, I dont think that the use of Environment.TickCount is very reliable... Environment.TickCount have a resolution of approx. 16 milliseconds on my machine (may vary on your machine), which is a very unfortunate number because 1000 / 30 is 33,333... and 16*2 is 32. So in your code the time between execution will be 16*3 (48) milliseconds... and that will give you 21 frames per second. Notice that it is 9 frames below the wanted framerate of 30 FPS! (You make it 10 :p) You'll want to do about 10 FPS over what you want for max. The loops always tends to go a bit slower then what's calculated. Maybe a windows api timer could solve the resolution problem, but I'm worried that WinAPI calls from VB.Net are slow...? - SysRq Quote
wyrd Posted August 11, 2003 Posted August 11, 2003 I don't know of any better timer then GetTickCount() and Environment.TickCount (which I believe are the same thing). http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemenvironmentclasstickcounttopic.asp .NET Framework Class Library Environment.TickCount Property Property Value A 32-bit signed integer containing the amount of time in milliseconds that has passed since the last time the computer was started. Remarks The value of this property is derived from the system timer and is stored as a 32-bit signed integer. Therefore, the elapsed time will wrap around to zero if the system is run continuously for 24.9 days. The resolution of the TickCount property cannot be less than 500 milliseconds. The TickCount property handles an overflow condition by resetting its value to zero. The minimum value returned by TickCount is 0. TickCount is different from the Ticks property, which is the number of 100-nanosecond intervals that have elapsed since 1/1/0001, 12:00am. Use the DateTime.Now property to obtain the current local date and time on this computer. http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sysinfo/base/gettickcount.asp Return Values The return value is the number of milliseconds that have elapsed since the system was started. Remarks The elapsed time is stored as a DWORD value. Therefore, the time will wrap around to zero if the system is run continuously for 49.7 days. If you need a higher resolution timer, use a multimedia timer or a high-resolution timer. To obtain the time elapsed since the computer was started, retrieve the System Up Time counter in the performance data in the registry key HKEY_PERFORMANCE_DATA. The value returned is an 8-byte value. For more information, see Performance Monitoring. Of note; If you need a higher resolution timer, use a multimedia timer or a high-resolution timer. I have no idea what sort of performance (speed wise) those timers give, but you can give them a try. which is a very unfortunate number because 1000 / 30 is 33,333 Don't you mean 1000 / 40. Quote Gamer extraordinaire. Programmer wannabe.
*Experts* Volte Posted August 11, 2003 *Experts* Posted August 11, 2003 [api]timeGetTime[/api] is apparantly accurate to the millisecond. [api]QueryPerformanceFrequency[/api] and [api]QueryPerformanceCounter[/api] are very very accurate indeed. All three are APIs. Quote
SysRq2000 Posted August 11, 2003 Author Posted August 11, 2003 High-resolution performance timer Well you can construct a much higher resolution performance timer by calling the windows api functions: QueryPerformanceCounter(out long) and QueryPerformanceFrequency(out long) Read this article from The Code Project, to learn how to construct your own high-resolution performance timer using windows api calls. :D I just don't know if there is an unknown cost by calling windows api functions from a loop in managed code? :confused: Maybe there is a better solution to the problem... I'm still open to suggestions! ;) Don't you mean 1000 / 40.No, I just used the original intended framerate of 30, and not the error-corrected value of 40, to explain why you have had to add 10 to get the correct framerate. Btw, if your TickCount resolution is 16 milliseconds, the true framerate will be 31.25fps when setting the intended framerate to 40fps. That is because the actual time between execution will be 32ms, and not 25ms as 40fps would suggest... ;) - SysRq Quote
SysRq2000 Posted August 11, 2003 Author Posted August 11, 2003 QueryPerformanceFrequency & QueryPerformanceCounter, the most accurate? [api]QueryPerformanceFrequency[/api] and [api]QueryPerformanceCounter[/api] are very very accurate indeed.I don't think it is possible to get any more accurate... am I wrong? - SysRq Quote
*Experts* Volte Posted August 11, 2003 *Experts* Posted August 11, 2003 No, it is as accurate as it can possibly be (potentially at least; system load might have some slight effect on it). Quote
wyrd Posted August 11, 2003 Posted August 11, 2003 I just don't know if there is an unknown cost by calling windows api functions from a loop in managed code? The only cost is that of calling the function. Calling a Windows API function should never be slower then calling an equivelent managed code function (ie; GetTickCount() or Environment.TickCount). You can always run minor benchmarking tests. No, I just used the original intended framerate of 30, and not the error-corrected value of 40, to explain why you have had to add 10 to get the correct framerate. Btw, if your TickCount resolution is 16 milliseconds, the true framerate will be 31.25fps when setting the intended framerate to 40fps. That is because the actual time between execution will be 32ms, and not 25ms as 40fps would suggest... Right, just as I said.. you need to add 10 to the desired FPS. :P The code I gave you would give the desired result, so I'm not sure what the explanation was for. BTW what type of game are you making? Quote Gamer extraordinaire. Programmer wannabe.
AndreRyan Posted August 11, 2003 Posted August 11, 2003 According to AllApi.Net QueryPerformanceCounter supposedly has a .Net equivelant, I'm not sure if this class actually is a QueryPerformanceCounter though. With FPS restrictions you'll want to spread them otherwise they'll bulk at the start (if the program runs at about 110 FPS) restricting to 40FPS means that for the last 300ms or so the program will not be interactive Quote .Net allows software to be written for any version of Windows and not break like Unmanaged applications unless using Unmanaged procedures like APIs. If your program uses large amounts of memory but releases it when something else needs it, then what's the problem?
SysRq2000 Posted August 11, 2003 Author Posted August 11, 2003 The game... BTW what type of game are you making?It's an unicycle game... But it's still very much in the design stage. I'm developing the game around various physic concepts to make the unicycle handling very realistic. Early gameplay tests done in Flash MX, seems very promising, and I can't wait to show you guys an alpha release of the game. I got the idea from the old, but very addictive game, "Elasto Mania". Check it out! - SysRq Quote
wyrd Posted August 11, 2003 Posted August 11, 2003 Sounds interesting. Can't wait to see it. :) Quote Gamer extraordinaire. Programmer wannabe.
davidrobin Posted August 14, 2003 Posted August 14, 2003 Thanks you guys, this is something I have been looking at too. Quote
shouzama Posted August 21, 2003 Posted August 21, 2003 Thanks you guys, this is something I have been looking at too. Same here! Quote
wyrd Posted August 23, 2003 Posted August 23, 2003 I found this excellent article; http://www.gamedev.net/reference/articles/article753.asp Quote Gamer extraordinaire. Programmer wannabe.
shouzama Posted August 25, 2003 Posted August 25, 2003 That's really an excellent article. I wonder however how can this Well, you must find the most accurate timer on you PC. You want a timer that updates no faster than every millisecond. x86 PCs have a nice hardware clock that runs at 1193180hz (1.13198 MHz), microsecond resolution. Find it and use it. Once you have a timer, you need to make it a floating-point precision timer (let's call it "ftime()"); use doubles for this, since most timers use 64-bit integers. For making a floating-point precision timer, just get the timer's value and divide by its rate: double ftime(void) { return super_fast_clock()/the_rate_of_the_clock; } be done in .NET... Quote
SysRq2000 Posted August 25, 2003 Author Posted August 25, 2003 To make a call to the hardware clock in vb.net use the following code. <DllImport("Kernel32.dll")> _ Public Shared Function QueryPerformanceCounter(ByRef lpPerformanceCount As Long) As Boolean End Function <DllImport("Kernel32.dll")> _ Public Shared Function QueryPerformanceFrequency(ByRef lpFrequency As Long) As Boolean End Function So a class could be formed like this... Public Class HighResolutionTimer Private m_Frequency As Long Private m_Count As Long Public Sub New() QueryPerformanceFrequency(m_Frequency) End Sub Public ReadOnly Property FTime() As Double Get QueryPerformanceCounter(m_Count) Return m_Count / m_Frequency End Get End Property <DllImport("Kernel32.dll")> _ Private Function QueryPerformanceCounter(ByRef lpPerformanceCount As Long) As Boolean End Function <DllImport("Kernel32.dll")> _ Private Function QueryPerformanceFrequency(ByRef lpFrequency As Long) As Boolean End Function End Class - SysRq Quote
SysRq2000 Posted August 25, 2003 Author Posted August 25, 2003 For you C# programmers check this page... Quote
shouzama Posted August 27, 2003 Posted August 27, 2003 THANK YOU! :eek: Well... SysRq2000... THANK YOU VERY MUCH! :) :) :) :) Quote
pjv Posted August 28, 2003 Posted August 28, 2003 Also check out: http://www.mentalis.org/soft/classes.qpx for lots of useful stuff like that (the StopWatch class will help here). Heh.. now that I can finally post again I can answer some of these things :). It's so frustrating having an answer and not being able to post it. Pete Quote
shouzama Posted August 28, 2003 Posted August 28, 2003 I really suggest everyone to checkout pjv's site. And I do not mean only the link, but the entire site. Quote
pjv Posted August 28, 2003 Posted August 28, 2003 It's not my site, I just posted the link to it ;) Thought I should be clear on that, Pete Quote
Optikal Posted August 28, 2003 Posted August 28, 2003 Just curious, why do you want to limit your framerate? typically games will allow the framerate to be as fast as the host computer can handle... Quote
pjv Posted August 28, 2003 Posted August 28, 2003 You limit the framerate so the game runs the same speed on everyone's computer (so long as they can get above the framerate you limit it too anyway). This is very important for fairness and testability, among other things. It's useful for timing purposes if you know that any pc (above min spec) is going to run at exactly the same speed. Pete Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.