.NET Redraw at 60 FPS?

You could try implementing a game loop.

http://blogs.msdn.com/tmiller/archive/2005/05/05/415008.aspx

The basic loop (slightly modified from his original version and the version in the new SDK for ease of reading):

public void MainLoop()
{
        // Hook the application’s idle event
        System.Windows.Forms.Application.Idle += new EventHandler(OnApplicationIdle);
        System.Windows.Forms.Application.Run(myForm);
}    

private void OnApplicationIdle(object sender, EventArgs e)
{
    while (AppStillIdle)
    {
         // Render a frame during idle time (no messages are waiting)
         UpdateEnvironment();
         Render3DEnvironment();
    }
}

private bool AppStillIdle
{
     get
    {
        NativeMethods.Message msg;
        return !NativeMethods.PeekMessage(out msg, IntPtr.Zero, 0, 0, 0);
     }
}

//And the declarations for those two native methods members:        
[StructLayout(LayoutKind.Sequential)]
public struct Message
{
    public IntPtr hWnd;
    public WindowMessage msg;
    public IntPtr wParam;
    public IntPtr lParam;
    public uint time;
    public System.Drawing.Point p;
}

[System.Security.SuppressUnmanagedCodeSecurity] // We won’t use this maliciously
[DllImport(“User32.dll”, CharSet=CharSet.Auto)]
public static extern bool PeekMessage(out Message msg, IntPtr hWnd, uint messageFilterMin, uint messageFilterMax, uint flags);

Simple, elegant, effective. No extra allocations, no extra collections, it just works.. The Idle event fires when there’s no messages in the queue, and then the handler keeps looping continuously until a message does appear, in which case it stops.. Once all the messages are handled, the idle event is fired again, and the process starts over.

This link describes one that uses the application's Idle event. It may be of use. You can simply perform a little time test or sleep to slow it down to your required fps. Try using the System.Diagnostics.StopWatch class for the most accurate timer.

I hope this helps a little.


Depending on what you are doing, have a look at WPF and it's animation support, it may be a better solution that writing your own amimations in WinForms.

Also consider using DirectX as it now has a .NET wrapper and is very fast, however it is harder to use the WPF or WinForms.

To continuously call your draw function:

  • Do the drawing in the repaint method
  • Add at the end of the repaint method do a BeginInvoke
  • In the delegate you passed to BeginInvoke, invalidate the control you are drawing

However your users may not like you killing their computer!

Application.Idle is also another good option, however I like the fact windows will slow down the rate it send WmPaint messages when needed.


The Windows Forms Timer is ultimately limited in resolution to the standard system clock resolution of your computer. This varies from computer to computer, but is generally between 1 ms and 20 ms.

In WinForms, whenever you request a timer interval in code, Windows will only guarantees that your timer will be called no more often then the number of milliseconds specified. It makes no guarantee that your Timer will be called at exactly the milliseconds you specify.

This is because Windows is a time-sharing OS, not real-time. Other processes and threads will be scheduled to run concurrently and so your thread will be forced to wait regularly for usage of the processor. Therefore you shouldn't write WinForms timer code that relies on exact intervals or delays of milliseconds.

In your situation, setting the interval to 1 ms is really just telling Windows to trigger this timer as often as it can. As you have seen this is definitely much less often than 1 ms (60fps = about 17 ms).

If you need a more accurate and higher resolution timer, the Windows API does provide high resolution/performance timers, if your hardware supports it, see How to use the high resolution timer. A drawback of this is that your application CPU usage will be increased to support the higher performance.

Overall I think you're better off implementing a hardware/system independent game loop. That way the perceived animation of your scene appears constant regardless of the actual frame-rate achieved. For more information these articles give a good background.

Tags:

C#

Winforms