[.net] C# and GUI threads

Started by
8 comments, last by nullsquared 14 years, 1 month ago
I'm confused about how to do a proper C# game loop. Once you create a Form, all the events are called automatically from a separate thread, as far as I can tell. So, where does my game loop go? If I put it in the main thread, then I might have issues when handling GUI events while my game loop is processing stuff. What is Application.DoEvents() used for considering it all happens automatically? (Just straight up C# and .NET stuff, no XNA or anything)
Advertisement
try a timer object and put your game code in the ontick event
Is there any other way of doing it?
Look at Tom Miller Loop
Quote:Original post by ragnarsun
Look at Tom Miller Loop


I've seen that. I'm just trying to find a cleaner, completely .NET based approach. I mean, come on, C# and .NET are so amazing that you can't do a proper game loop without invoking native win32 functions?
Quote:Original post by nullsquared
Quote:Original post by ragnarsun
Look at Tom Miller Loop


I've seen that. I'm just trying to find a cleaner, completely .NET based approach. I mean, come on, C# and .NET are so amazing that you can't do a proper game loop without invoking native win32 functions?


Not really. All other approaches allocate memory, use up too much CPU time or are wildly inaccurate from a timing-perspective.

The only other approach is to spawn a different thread and do your work on that. Do note that you won't be able to access the main Form directly (you'll have to use BeginInvoke and the like), but this approach works and is "clean".

On the other hand, Tom Miller's loop is simpler. Don't let the p/invoke scare you off, I've been using this approach successfully for years on all all major operating systems (Windows, Linux, OSX, porting the loop is straightforward).

[OpenTK: C# OpenGL 4.4, OpenGL ES 3.0 and OpenAL 1.1. Now with Linux/KMS support!]

Quote:Original post by Fiddler
On the other hand, Tom Miller's loop is simpler. Don't let the p/invoke scare you off, I've been using this approach successfully for years on all all major operating systems (Windows, Linux, OSX, porting the loop is straightforward).


Okay, guess I'll just go with that then. It's not scary, I just thought that .NET would have something just as good built in [grin].

And out of curiousity, what do you mean you've been using this approach on several OS's? I thought the whole PeekMessage() idea would only work on Windows?
I've done this. Don't use the Timer component. Instead use a Thread timer.

See usage for a .Net render surface here and create your own OnPaint event.
private System.Threading.Timer frameTimer;private System.Threading.TimerCallback frameTimerCallback;private int frameNumber = 0;  //what number frame are we currently on? 0..60private const int frameRate = 60;public RenderSurface()  //constructor{  InitializeComponent();  this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);  this.SetStyle(ControlStyles.ResizeRedraw, true);  this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);}public void Begin(){  this.frameTimerCallback = new System.Threading.TimerCallback(frameCallBack);  this.frameTimer = new System.Threading.Timer(this.frameTimerCallback);  this.frameTimer.Change(0, 1000 / frameRate);   //start immediatly. }private void frameCallBack(object obj){  this.frameNumber++;  if (frameNumber >= frameRate)    this.frameNumber = 0;  this.Invalidate();  //calls Paint which triggers a render}



Quote:Original post by nullsquared
Quote:Original post by Fiddler
On the other hand, Tom Miller's loop is simpler. Don't let the p/invoke scare you off, I've been using this approach successfully for years on all all major operating systems (Windows, Linux, OSX, porting the loop is straightforward).


Okay, guess I'll just go with that then. It's not scary, I just thought that .NET would have something just as good built in [grin].

And out of curiousity, what do you mean you've been using this approach on several OS's? I thought the whole PeekMessage() idea would only work on Windows?


Yes, but every OS provides a way to query for pending messages. For example, on Linux (and everything else that has an X server), you can use XPending. The implementation is slightly more complicated, because you need to gain access to the Form's private display connection but it's not too bad. For comparison: Windows implementation vs Linux implementation (you only need lines 35-36, 81-86 and 111-114 of the Linux one, the rest have to do with OpenGL initialization and are not relevant here).

Usage looks like this:
Application.Idle += (sender, e) =>{    while (control.IsIdle)    {        // update and render    }};

[OpenTK: C# OpenGL 4.4, OpenGL ES 3.0 and OpenAL 1.1. Now with Linux/KMS support!]

Quote:Original post by Fiddler
Quote:Original post by nullsquared
Quote:Original post by Fiddler
On the other hand, Tom Miller's loop is simpler. Don't let the p/invoke scare you off, I've been using this approach successfully for years on all all major operating systems (Windows, Linux, OSX, porting the loop is straightforward).


Okay, guess I'll just go with that then. It's not scary, I just thought that .NET would have something just as good built in [grin].

And out of curiousity, what do you mean you've been using this approach on several OS's? I thought the whole PeekMessage() idea would only work on Windows?


Yes, but every OS provides a way to query for pending messages. For example, on Linux (and everything else that has an X server), you can use XPending. The implementation is slightly more complicated, because you need to gain access to the Form's private display connection but it's not too bad. For comparison: Windows implementation vs Linux implementation (you only need lines 35-36, 81-86 and 111-114 of the Linux one, the rest have to do with OpenGL initialization and are not relevant here).

Usage looks like this:
*** Source Snippet Removed ***


Very cool, thanks for the information!

This topic is closed to new replies.

Advertisement