What is the proper implementation of "quit on X-out" in windowed games?

Started by
6 comments, last by rip-off 12 years, 6 months ago
I've just started to code simple games with help from the 'Lazy Foo' articles.

To quit the program on an X-out, he keeps a quit variable in his main function and all the main loops break out in case the quit variable is 'true'.

This seemed very reasonable at first but as my codes grew in size, it got too tiring to implement "return something to the main function in case user X'ed out so the main function can set the quit variable to true".


Is it proper practice to;

1- Define the quit variable globally so i can set it easily from within each function.

2- Implement a seperate function that frees the memory, cleans up and quits with "exit()", so i don't bother with a variable but just call that function .


One can choose to do things as he/she likes and the proper way depends on the circumstance but i was wondering if these methods are of the the "stay away if you do not realy need them" kind.
Advertisement
Your looking for the "correct" way of doing it..
I am not sure if this is the correct way of doing it but its what I do =)

In the event of a fatal error etc etc I just send a PostQuitMessage(errorcode)

And Take care of it in my windows message proc when I see WM_QUIT


edit: Something like this for your message pump
MSG msg;//message structure
for(;;) //message pump
{
//look for a message
if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
{
//check that we arent quitting
if(msg.message==WM_QUIT) break;
//translate message
TranslateMessage(&msg);
//dispatch message
DispatchMessage(&msg);

}
else
{
if ( Program_Running() == 0) // good call
{//This is just example code, Program_Running() would make its own call to PostQuitMessage with its errorcode

}
else //bail out we had a error
{
MessageBox(NULL, "Failed in Program_Running()" , "Fatal Error", MB_OK);
PostQuitMessage(99);
}
}

}
Generally, you want only one input loop, and this loop isn't too "far" from your main loop. You shouldn't need to pass this variable up through too many layers. One option is to use a callback/functor to handle this. My input systems are generally mappings of events to functors, in this case the functor can set a quit flag higher up.

I wouldn't go with a global quit variable. An exit function will not correctly clean up all resources, you should allow this to happen as the stack naturally unwinds so that RAII resources are destroyed.

To be honest, if this is causing you trouble in simple games I suspect you are vastly over-engineering the solution.
A quit flag is a good way to do it. The problem comes when you have many things that can cause that flag. Try to reduce that, when my window closes I catch some kind of exit event (using Ogre3d). The other way I quit is if my game state machine is empty (if the game isn't in any state then just quit). You could pass the quit flag around by reference if you need to but I would focus more on reducing what can actually exit the game.

Interested in Fractals? Check out my App, Fractal Scout, free on the Google Play store.

The only correct way of exiting is making sure everything in your program is cleaned up and nothing is dangling. Do it the way it makes sense to you. It's like if you told 5 separate people to sketch a picture of an alien, there isn't 1 correct answer, there would just be 5 different interpretations of an alien : )
[size="2"]More sprinkles!
@ yewbie : Thanx. I do not use win API. Though from what i understand, you happen to send a message to windows that you want to terminate ( with PostQuitMessage() ) . And what do you do in your main() to quit? Or does windows take the leash from there on and just terminates your app?..


Generally, you want only one input loop, and this loop isn't too "far" from your main loop. You shouldn't need to pass this variable up through too many layers. One option is to use a callback/functor to handle this. My input systems are generally mappings of events to functors, in this case the functor can set a quit flag higher up.

I wouldn't go with a global quit variable. An exit function will not correctly clean up all resources, you should allow this to happen as the stack naturally unwinds so that RAII resources are destroyed.

To be honest, if this is causing you trouble in simple games I suspect you are vastly over-engineering the solution.


@rip-off: So it's better to go on with the quit flag in the main and check my implementation again if i end up passing the quit variable for too many layers. Thanx, that was what i needed to hear..


A quit flag is a good way to do it. The problem comes when you have many things that can cause that flag. Try to reduce that, when my window closes I catch some kind of exit event (using Ogre3d). The other way I quit is if my game state machine is empty (if the game isn't in any state then just quit). You could pass the quit flag around by reference if you need to but I would focus more on reducing what can actually exit the game.


@Nanoha: Nope, it's the X-out that was bothering me.. When i am in a get_sting_input function thats in the hi_score_menu function thats in the game_over_scene function thats in the main function and the user just presses the exit button of the window, it was a pain to get the quit flag to main.. But from what i understand, it's not the implementation of quit thats wrong, its that i'm layering too much..

@ yewbie : Thanx. I do not use win API. Though from what i understand, you happen to send a message to windows that you want to terminate ( with PostQuitMessage() ) . And what do you do in your main() to quit? Or does windows take the leash from there on and just terminates your app?..


PostQuitMessage sends at WM_QUIT message and in my code during the message loop (on the next frame) WM_QUIT is processed and breaks the "infinite" while loop.
Your answer is very Win32 specific, yewbie. I think that the generalisation of your answer, applicable to SDL, is to have one "master" event loop, which I would agree with.


When i am in a get_sting_input function thats in the hi_score_menu function thats in the game_over_scene function thats in the main function and the user just presses the exit button of the window, it was a pain to get the quit flag to main.. But from what i understand, it's not the implementation of quit thats wrong, its that i'm layering too much..
[/quote]
This sounds like get_string_input has its own input loop?

I would generally model it differently. For simple games, game over/high score are not functions, but states. Control is continually passed from the main loop into the active state: to react to input, update and render.

In simple games the active state can be an enumeration, with a switch in main() to pass control to the correct states. Something like this:

enum GameState
{
MainMenu,
RunGame,
GameOver,
HighScore,
Exit
};

int main(...)
{
setup();

GameState current = MainMenu;
while(current != Exit)
{
SDL_Event event;
while(SDL_PollEvent(&event))
{
switch(current)
{
case MainMenu: handleMenuEvents(event); break;
case RunGame: handleGameEvents(event); break;
case GameOver: handleCutSceneEvents(event); break;
case HighScore: handleHighScoreEvents(event); break;
}
}

GameState next = current;

switch(current)
{
case MainMenu:
next = updateMenu();
renderMenu();
break;

case RunGame:
next = updateGame();
renderGame();
break;

case GameOver:
next = updateCutScene();
renderCutScene();
break;

case HighScore:
next = updateHighScore();
renderHighScore();
break;
}

if(current != next)
{
transition(current, next);
current = next;
}
}
cleanup();
}

In more complex games with lots of per-state information, I might model each state as a class that implements an interface, with pure virtual update(), onEvent() and render() member functions. I would use a class to leverage RAII for setup/teardown of the per-state data.

This topic is closed to new replies.

Advertisement