Jump to content
Xtreme .Net Talk

Recommended Posts

Posted

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

Posted

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.

Gamer extraordinaire. Programmer wannabe.
Posted

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

Posted

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.

Gamer extraordinaire. Programmer wannabe.
  • *Experts*
Posted

[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.

Posted

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

Posted

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

Posted

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?

Gamer extraordinaire. Programmer wannabe.
Posted

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

.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?
Posted

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

Posted

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...

Posted

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

Posted

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

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...