1

I'm creating a simple game using GDI+ in C#.

First of all I need a game loop, and a render loop. I've decided to break these in to two seperate threads. It seems to work, and runs extremely fast, but the reason I'm asking here is because I see people use timers for their game loops to make them run at a specific frame rate.

This obviously has the advantage, that you can be sure of the speed in which actors move. But my game loops just runs as fast as possible, like the Update function in Unity3D. Now to make sure that actors always move at the same speed, all I have to do is to multiply the move speed by the frame delta time (the time between each frame).

My render loop also runs as fast as possible. Is this a good game loop, why or why not?

// Constructor
public FormDisplay()
{
    // Create a thread object, passing in the GameLoop method
    var gameThread = new Thread(this.GameLoop);

    // Start the game thread
    gameThread.Start();

    // Create a thread object, passing in the GameLoop method
    var renderThread = new Thread(this.RenderLoop);

    // Start the render thread
    renderThread.Start();
}

private void GameLoop()
{
    while (true)
    {
        // TODO: Insert Game Logic
    }
}

private void RenderLoop()
{
    while (true)
    {
        // TODO: Insert Render Logic
    }
}
Soeholm
  • 1,102
  • 14
  • 15
  • I don't have any actual game programming experience, but my gut feeling is that it's probably better to "push" updates to the rendering instead of polling for it. What I mean is, can you notify the UI if something changes and have it act accordingly? So you don't waste CPU cycles when nothing on the screen is changing and the user is idling. Maybe this isn't a great idea, as I said, no experience, just a hint. – Davio Nov 08 '12 at 13:36
  • Seems to me you have *three* threads here: the GameLoop thread, the RenderLoop thread, and *the main thread* that's spawning the other two... – cHao Nov 08 '12 at 13:36
  • @Davio: Most 3Dish games have to push a whole scene when anything changes. (The OpenGL and Direct3D APIs make it that way, anyway.) If *anything at all* changes in the scene, the whole thing needs redisplaying. – cHao Nov 08 '12 at 13:38
  • If you don't have any throttling within your `while(true)` each thread will run at 100% CPU load which slows down maybe other threads you need in the future (e.g. KI) and also the whole system without doing anything meaningful. – Oliver Nov 08 '12 at 13:40
  • Oh yeah @cHao, you're right, I have three threads :-) – Soeholm Nov 08 '12 at 13:42
  • What kinds of things are each loop doing? Is there a reason for the game loop not to be more event driven, or the render loop not to be tied to a timer? You generally want to be a good citizen and use only as much CPU as you need, and letting those loops block when they don't have to be doing something accomplishes that to some degree. (Also makes your game more friendly to low-end machines.) – cHao Nov 08 '12 at 13:42
  • @Davio The renderloop is running at about 60 fps ATM, I think that is fine. And there'll probably be happening something on the screen all the time, as I'm creating a Tower Defense.. So I'm not sure if it'll be a good idea to call on the render manually. – Soeholm Nov 08 '12 at 13:43
  • Ok, as long as you thought about it. :) – Davio Nov 08 '12 at 13:46
  • @Oliver Hmm, I was told that wasn't a problem when creating multiple threads. I saw an implementation where the while loops where paused for one millisecond with Thread.Sleep(1). I'm not sure if that is what you been by 'throttling'. I don't know the word tbh – Soeholm Nov 08 '12 at 13:46
  • I think you should move this thread to [codereview](http://codereview.stackexchange.com) – 2pietjuh2 Nov 08 '12 at 13:49
  • @Soeholm: Yes, with throttling i mean some kind of sleep. This is a problem. Maybe on multi-core machines not such a big one, but even their you reach the limits quite fast (don't use more thread than cores available). – Oliver Nov 08 '12 at 13:50
  • @Soeholm: What he means by "throttling" is basically blocking when you don't need to run, so you're not hogging the CPU. `Thread.Sleep(1)` would yield, but i'm of the opinion that sleeping at all hints at a race condition waiting to happen. Suddenly your code's dependent on *external* time rather than *CPU* time, and all sorts of hilarity ensue when the two get confused. – cHao Nov 08 '12 at 13:51

2 Answers2

1

You should consider your screen refresh rate as your limiting factor. There is no point moving your actors 300 times a second if your screen only updates 100 times a second.

Likewise, rendering the screen 300 times a second when the monitor refresh rate is only 100 Hz may show tearing. This happens when you update the frame buffer while the buffer is being present to the screen, so the top half of your actor appears in the old place, the bottom part in the new place.

A good article about reducing flicker is Stack Overflow question Reduce flicker with GDI+ and C++.

Ideally, as a general game loop, your game thread should be processing and building a list to pass to the render thread for the next screen refresh (that is, you're always processing for the next displayed frame). Both threads then wait for the next frame. This of course means you need to know when that happens - which I don't think you can find out rendering using GDI+.

Community
  • 1
  • 1
  • I use double buffering, which takes care of the flickering pretty good. I was considering having a list of sprites, and then call a render method on all of them in the render loop. I have to use GDI+, because its a school project. I'm still not sure if you want the game loop to run as fast as possible, or if that's just wasting CPU cycles. – Soeholm Nov 08 '12 at 14:23
  • Its wasting CPU cycles. If I were writing it, I would try to run the game loop once per screen refresh, ideally synchronised to the refresh. Personally I would also still use time based positioning as you suggest so that dropped frames dont matter as much. – Steven Mortimer Nov 08 '12 at 14:27
1

The idea of jumping straight to managing your own threads without any understanding of how the libraries themselvees (or .NET GUI) uses threading) seems like a bad idea.

I'm sure you will need threading, but I'm not sure you would need to explicitly manage it yourself. Let the underlying libraries take care of that and push work to/from the main UI thread.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jason Meckley
  • 7,589
  • 1
  • 24
  • 45
  • I can't really see why I shouldn't manage my own threads.. I might not be that experienced using threads, but at least I'll learn something. Pushing or pulling from the main UI threads sounds more complex tbh :-) – Soeholm Nov 08 '12 at 14:18
  • multi-threading is the same no matter which threads you are crossing. better to use the built-in mechanics, rather than recreate the wheel. take a look at some of ayende's thoughts on the subject: http://ayende.com/blog/search?q=multithread – Jason Meckley Nov 08 '12 at 14:48