Jump to content
  • Advertisement
Sign in to follow this  
Si Robertson

Game States - Alternate Rendering Based on Visible States

This topic is 3785 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi guys, I have been browsing through all of the good "game state" threads I could find here, but I have a question that doesn't seem to be covered in the threads I have seen. Let's say I have two game states, GameState and GameMenuState. The GameMenuState is used for the main menu as well as the in-game menu (i.e. it is rendered over GameState ). The thing is, the in-game menu needs to have one or two menu items hidden, those items might be "Credits" and "Bonus Items" for example which should only be displayed on the main menu. The question is, should I (a) create an InGameMenuState class even though it will be doing exactly the same thing as GameMenuState, (b) create an InGameMenuState class as a subclass of GameMenuState and hide/flag the items that shouldn't been shown (via the class constructor)? Alternatively, is there a clean way of telling GameMenuState that it is being rendered above GameState, thus allowing it to hide/flag the menu items, if so is this something you would suggest doing? Thanks, Si ++

Share this post


Link to post
Share on other sites
Advertisement
You may find this helpful: Game State Management Sample. It's in C# and uses the XNA Framework, but it should prove to be an interesting study.

It seems they solve one of your problems this way:

        /// <summary>
/// Normally when one screen is brought up over the top of another,
/// the first screen will transition off to make room for the new
/// one. This property indicates whether the screen is only a small
/// popup, in which case screens underneath it do not need to bother
/// transitioning off.
/// </summary>
public bool IsPopup
{
get { return isPopup; }
protected set { isPopup = value; }
}

bool isPopup = false;

Share this post


Link to post
Share on other sites
Thanks for the reply, Maxamor.

I think I may know of an easy way to handle this now. I'm obviously using a game state stack for this, and the stack knows when a game state is pushed/added/popped etc. So, my idea is to give each game state a stackIndex property that is set by the stack whenever the order and/or length of the stack changes, that way the GameMenuState will be able to hide/show menu items based on it's stackIndex value. If the value is 0 (zero) the full menu will be shown (0 = main menu), if the stackIndex value isn't 0 then the alternative in-game menu is shown.

Share this post


Link to post
Share on other sites
It would be more robust to be able to query for the presence of a given state further up the stack (eg. the 'gameplay' state), rather than assigning special meaning to fixed stack indexes. Otherwise your system has to be refactored when you add extra intermediate states.

Share this post


Link to post
Share on other sites
Good point. In that case maybe I should give each game state a getName() method that returns the name/id of the game state. I can't check for class names really (and would prefer not to) because the game state stack only cares about the IGameState interface that each game state implements, the stack isn't interested in the actual classes used.

Sounds like a good way to do things. Thanks for the replies guys. :)

Share this post


Link to post
Share on other sites
I'm doing this in c++:







class GameState
{
protected:
//i has a renderer
//i has a kb and mouse object
//i has lots of other stuff
public:

virtual void game_loop(){};

};


class MenuGameState: public GameState
{
MenuGameState:(renderer * r, input_object * i ........)
{
load_stuff_only_this_gamestate_has();
};

~MenuGameState()
{
delete_stuff_only_this_gamestate_has();
}

void game_loop(){
//do stuff

while(nobody_presses_ESC){
do_menu_like_stuff()
}

return;
}
};





class PlayingGameState: public GameState
{
PlayingGameState(renderer * r, input_object * i ........)
{
load_stuff_only_this_gamestate_has();
};

~PlayingGameState()
{
delete_stuff_only_this_gamestate_has();
}

void game_loop(){
//do stuff

while(we don't want to exit){
if(somebody pressed ESC){
GameState NS = new MenuGameState(render, input.....);
NS->game_loop();
delete NS;
}
}

return;
}
}




So, each gamestate launches a different gamestate, and goes into the loop for that gamestate. If you are playing and you press ESC the game creates a new MenuGameState, and calls the game_loop method, and they merrily click stuff. When they press esc again, the game_loop method returns, and the previous gamestate then optionally deletes the gamestate.

If you dont delete it, you won't need to reload the menu stuff each time they press escape. You could create an instance of MenuGameState when PlayingGameState starts up, and delete it in the destructor. Its a very flexible system.

When you first start the game, it goes into the MainMenu gamestate which, after the correct options are selected, launches a PlayingGameState with whatever parameters the user selected. Notice how many games won't let you into the main menu if your playing a game currently, and the in game menu is a different menu entirely? Now you know why.


Share this post


Link to post
Share on other sites
Ew. Strongly recommend you implement the loop outside. Otherwise, you'll replicate it for each state, and have weird recursive-ness going on.

Make each update function do one iteration, and *return* the state that the game will be in as a result - either 'this', NULL (meaning program = over, OS = very yes) or a newly constructed instance of another derived class. std::auto_ptr should be sufficient to take care of the memory management, if I'm thinking clearly:


class GameState {
protected:
// you probably shouldn't has too much stuff here; pass it in to update
// instead.
public:
virtual std::auto_ptr<GameState> update() = 0; // don't allow instantiation!
virtual ~GameState() {} // important for polymorphic classes!
};


class MenuGameState: public GameState {
// blablabla
std::auto_ptr<GameState> update() {
do_menu_like_stuff();
if (somebody_presses_ESC) {
return new PlayingGameState();
}
return this; // std::auto_ptr guards against this; I checked
}
};

class PlayingGameState: public GameState {
// blablabla

std::auto_ptr<GameState> update() {
do_game_stuff();
if (somebody_presses_ESC) {
return NULL;
}
if (player_sux_teh_big_one_one_one_one) {
display_message("ZOMG GAEM OVAR");
return new MenuGameState();
}
return this; // std::auto_ptr guards against this; I checked
}
}

int main() {
// Simplicity itself:
for (std::auto_ptr<GameState> state = new MenuGameState(); state;
state.reset(state->update())) {}
}




Note that this does not cover proper separation of updating and rendering; that's left as an exercise.

Quote:
Notice how many games won't let you into the main menu if your playing a game currently, and the in game menu is a different menu entirely? Now you know why.


No; that's a UI design issue. The in-game menu logically needs different options: "new game" probably shouldn't be there (unless you want to imply giving up on the current one) and "resume current game" probably should (and can't be in the main menu; resume what game?).

Share this post


Link to post
Share on other sites
Quote:
Original post by Zahlman
Ew. Strongly recommend you implement the loop outside. Otherwise, you'll replicate it for each state, and have weird recursive-ness going on.


I don't follow, can you give an example? The system is that int main() simply creates an instance of the main menu gamestate, which instantiates the classes itneeds and in turn and at the appropriate time initialises other game states.

The ingame menu doesn't instantiate another PlayingGameState, but rather the function game_loop() just returns, relying on the fact that the caller of game_loop() is prepared for any consequences. It is aware of its caller's message buffer, and is able to pass a message "back" as well as having its own local message buffer.

Quote:

Make each update function do one iteration, and *return* the state that the game will be in as a result - either 'this', NULL (meaning program = over, OS = very yes) or a newly constructed instance of another derived class. std::auto_ptr should be sufficient to take care of the memory management, if I'm thinking clearly:

*** Source Snippet Removed ***

Note that this does not cover proper separation of updating and rendering; that's left as an exercise.

Quote:
Notice how many games won't let you into the main menu if your playing a game currently, and the in game menu is a different menu entirely? Now you know why.


No; that's a UI design issue. The in-game menu logically needs different options: "new game" probably shouldn't be there (unless you want to imply giving up on the current one) and "resume current game" probably should (and can't be in the main menu; resume what game?).


I guess you are right, I haven't really seen the code of enough other games to comment on this, and I should withdraw that statement. But I know that some games use a totally different menu for the in-game menu to the main menu.

Share this post


Link to post
Share on other sites
Quote:
Original post by Zahlman
"resume current game" probably should (and can't be in the main menu; resume what game?).


The last game played, quite commonly used in games.

Share this post


Link to post
Share on other sites
Quote:
Original post by marius1930
Quote:
Original post by Zahlman
"resume current game" probably should (and can't be in the main menu; resume what game?).


The last game played, quite commonly used in games.
Really? I've never seen a game with a 'resume game' item in the main menu that returned you to the last game you were playing (with many types of games that wouldn't even make sense).

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!