Qua TD II: The Game Loop

Picking up from the specifications of the TD in the last post we’ll continue with a discussion and implementation of a game loop for the game in this post.

As I’m hoping to put together the project in such way that it’s possible to visually see how the game evolves as early in the process as possible, I’m going to start out talking about the choice of game loop. Since the game is to be written using Windows Forms I figured that the project will be using one of the following three game loops methods:

  • A simple while loop that makes use DoEvents;
  • use a timer with a high frequency of ticks;
  • or abuse the Application.Idle event alongside with the PeekMessage API.

In my opinion, the two first options can quickly be described as utterly royal fail

FAIL

FAIL

but I’ll go through all three methods explaining why I eventually end up with my choice of game loop.

DoEvents()

DoEvents (DE) is properly by far the easiest solution to a working game loop as it can be coded in a single line. You can setup a while loop and put a DE call into it and you’re basically done… However, there are several disadvantages to using this approach. When calling DE in a loop, resources are being allocated by the call that the garbage collector is not capable of cleaning up which means that you’ll be facing performance issues at some point. There has even been reports of memory leaks as bad as 1 MB / 5 seconds when visual styles is enabled. Overall this solution is bad for performance but easily implemented.

Timers

Timers are bad! The timer classes in .NET (and most other timers for that matter) has the possibility of running out of sync when the machine is under heavy performance loads or when the frequency of the computer changes due to power management features. Furthermore the timers in .NET will raise a tick event even if the previous tick method wasn’t done execution which means you could possibly get a game loop that was running on several different threads producing utterly unpredictable results so I would definitely avoid using timers as there really is not advantages to them used for this purpose and they weren’t created for this kind of use.

PeekMessage & Application.Idle

I find this solution by far the most efficient. Windows Forms are event driven and in it’s basic it has a while loop checking for incoming messages to the window such as to close, to move it and such. When you handle the Application.Idle event you’re sure that your form is not supposed to be doing anything else when entering the game loop. Inside your game loop PeekMessage allows you to make sure the the form is still idle while continuing to execute the game loop. By combining the two you get full responsiveness in your application without any memory leaks or other dirty solutions. So this IMO is by far the best solution as it takes advantage of the windows forms loop and does not lock up the application.

Creating the Game Loop

The first thing we’ll need to get a game loop up and running is the reference to PeekMessage. I’ve decided to encapsulate this in a static class called Win32. For those of you unfamiliar with PeekMessage what it does is to check if there is any incomming messages to the current form such as a request to close or move the form. If there is no such messages in the queue, it will return false. Thus everytime PeekMessage returns false, we are free to continue with the game loop:

namespace QuaTD.Utilities
{
using System;
using System.Runtime.InteropServices;

public static class Win32
{
public const int PM_NOREMOVE = 0;

[System.Security.SuppressUnmanagedCodeSecurity]
[System.Runtime.InteropServices.DllImport("User32.dll", CharSet = CharSet.Auto)]
public static extern bool PeekMessage(
out peek_message msg,
IntPtr hWnd,
uint messageFilterMin,
uint messageFilterMax,
uint flags);

[StructLayout(LayoutKind.Sequential)]
public struct peek_message
{
public IntPtr hWnd;
public IntPtr msg;
public IntPtr wParam;
public IntPtr lParam;
public uint time;
public System.Drawing.Point p;
}
}
}

With that in place, we can now create a function IsAppIdle() that will use PeekMessage to check whether the application is available for doing more game looping.

public bool IsAppIdle()
{
Win32.peek_message msg;

return !Win32.PeekMessage(out msg, IntPtr.Zero, 0, 0, Win32.PM_NOREMOVE);
}

Now we’re ready to put together the actual game loop which will be started by the Application.Idle event, and will continue as long as the application is idle. Once the application again becomes idle, the game loop will continue.

First we must hook up the Application.Idle event which is raised everytime the form goes into an idle state (thus having no more messages in the queue to be processed) and we shall remember to unhook this event once our application closes to prevent memory leaks:

public GameForm()
{
InitializeComponent();

Application.Idle += new EventHandler(Application_Idle);
this.FormClosing += new FormClosingEventHandler(GameForm_FormClosing);
}
void GameForm_FormClosing(object sender, FormClosingEventArgs e)
{
Application.Idle -= new EventHandler(Application_Idle);
this.FormClosing -= new FormClosingEventHandler(GameForm_FormClosing);
}

And the game loop itself:

void Application_Idle(object sender, EventArgs e)
{
do
{
if (ActiveForm != this)
System.Threading.Thread.Sleep(200);
GameLoop();
}
while (this.IsAppIdle());
}

This concludes the choice and implementation of game loop for Qua TD. Modification to the game loop will eventually arise later on in the process, but at least now the basics are set for continuing the development of the game.

About these ads

3 Responses to “Qua TD II: The Game Loop”

  1. Johnny JAck Says:

    LOL, man down! Man down!

    RT
    http://www.real-anonymity.pro.tc

  2. Eradicator Says:

    I’ll be watching this, however, can you find a nicer way to show code? Maybe it’s just me, but i’m finding it really hard to read.

  3. Qua Says:

    I know the formatting is ugly, but I don’t think I can use plugins @ wordpress.com, so for now I’ll be using their built-in formatting.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: