views:

401

answers:

2

Hi!

I have for a school assignment created a small game, it is divided into 2 different projects, one project with the form and one with a DLL-file containing the game.

The game loop is very simple and looks like this:

private void GameLoop(Graphics g)
    {
        int lastTick = Kernel32.GetTickCount();
        do
        {
            if (terminated)
                break;

            while ((lastTick + 50) > Kernel32.GetTickCount())
                Application.DoEvents();

            while (gamePaused)
                Application.DoEvents();

            g.FillRectangle(new SolidBrush(Color.White), 0, 0, 800, 640);
            DrawWalls(g);
            MoveMonsters();
            DrawMonsters(g);
            lastTick = Kernel32.GetTickCount();
        }
        while (true);
        gameRunning = false;
    }

It works as intended and redraws the panel on the form page. On the form page i have a button to quit the current game, this is done simply by the main form calling the game.dll's command TerminateGame() witch set's terminated to true, this also works as intended. Now my problem is when the user clicks on the form close button or presses F4.

Then i tried to do the same thing:

private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
    {
        if (game.IsRunning)
            game.TerminateGame();            
    }

But then i keep getting this error: A generic error occurred in GDI+. and it points to this line: g.FillRectangle(new SolidBrush(Color.White), 0, 0, 800, 640);

I have no idea why it works when i press the button that just terminates the game and why its not working when the Form is closing, its the same method call.

The form closes perfectly if i first press the button and then press F4, it's just when i just press F4 that i keep getting this.

Any ideas?

A: 

You need to wait for the gameloop to terminate. If you don't, then code will get executed after various graphics objects have already been disposed which throws the exception you're recieving. To fix this, wait until the game loop has terminated, and then let your application terminate.

Like

if (game.IsRunning)
     game.TerminateGame();
while (game.IsRunning)
    Continue;
Qua
+6  A: 

Your main error (IMO) is creating a game loop yourself and calling Application.DoEvents. Instead, you should let the normal UI event loop itself run (via Application.Run(form), and add timers for the animation etc. WinForms is designed to run in an event-driven way.

The reason one is failing is because you're trying to draw after the form has actually been closed - i.e. you're drawing on an invalid Graphics handle. When the "terminate" button is pressed, I assume you're not actually closing the form, hence the lack of the problem.

A quick and dirty hack would be to add another:

if (terminated)
    break;

after the last call to Application.DoEvents, before you try to draw on the Graphics - but that's not tackling the more fundamental way that you're effectively trying to use WinForms in a way it wasn't really designed for.

Jon Skeet
So i should take out the game loop and put it into the windows form instead?The only reason i put it there was that we needed to have at least one DLL-file in the project.
Patrick
The "loop" should be implicit by running the form. That's how WinForms works: the loop is run by WinForms until the main form closes. For timed occurrences (e.g. monsters moving) you use a timer. Everything else is event driven. Timers aren't exactly high precision, but should be good enough for a school project.
Jon Skeet
Ok, thanks. I will move the game loop to the form instead.
Patrick