Game state machine (Rendering question)

Started by
6 comments, last by Bob Janova 18 years, 1 month ago
I'm trying to design an OO engine and want to get the design just right before I start any implementation and I've got a quick question about people's views on having a state use another state. For example, say I have an interface IState for a class CState, which defines functions like: Enter Exit Update Render Then say that there are two states in a game, CInGameState and CMenuState. Obviously the states render the in game view and menu respectively. Now say I want to fade between the two, i.e. when the player presses escape, the menu fades in. What would be the best way (from a design point of view) for this to be allowed. Should one state's Render function be allowed to call another state's one? So that CMenuState::Render would call CInGameState::Render? Or should the programmer have to replicate the render function from the CInGameState class in the CMenuState one? I'm talking about this from a purely design point of view. I'm aiming to make the engine to be as robust, clean and modular as possible?
Advertisement
Whoever owns the states should call both states' Render method during a fade?
But shouldn't it be up to the state itself to decide what to render? I'd like to have a more general solution, so that a state can do other things like layer itself on top of another state's rendered output (e.g. a message box or something).
Personally, I'd look towards a decorator sort of pattern here.

class FadeTransition:State{    private State From;    private State To;    public override void Update(){        if(To.alpha!=255){            // increment fade        }else{            // This might be tricky, depending on how you're            //  doing things.            Exit();        }    }    public override void Render(){        From.Render();        To.Render();    }       public override void Exit(){        Iterator MyGameStatePosition=GameStates.Find(this);        if(MyGameStatePosition.IsValid()){            MyGameStatePosition=To;            // possibly unreference To.        }        // possibly delete this/from.    }    public FadeTransition(State FromState, State ToState){        Iterator FromGameStatePosition=GameStates.Find(FromState);        if(FromGameStatePosition.IsValid()){            FromGameStatePosition=this;        }        From=FromState;        To=ToState;        // Set fade effect data.    }}
I dont think if my methoid is right either,in my game loop i have something like:

global in_game,menu;

if(in_game)
{
process_game();
render_geometry();
}
if(menu)
{
process_menu();
draw_menu();
}

here i can make the game so it can play at the same time I am in the menu(for example in multiplayer game without a Pause button) . I may do additional check in process_game() for the menu variable and lock the in_game controls if necessary.
I recommend doing something along the lines of what Telastyn has suggested. Take the fade logic out of the states, and relegate it to a specific fading mechanism. In an OO design, the states should be as modular and self-contained as possible.
I like you state system - I've just moved over to something like that myself. Also including functions "OnMouse" and "OnButton" etc. in the state.
One way to do multiple states is to use something like "PushState" as well as "SetState". So you are in the game, and you press the "Options" button, you "PushState" to the options dialog - this leaves both states active to some extent. The "Options" state can do soemthing like "if there is a parent state, render that first, now render myself over the top". When you press the "ok" button, you "pop state". This works well for re-using the options dialog from the main menu as well as in game. Also works well for pausing etc. within the game.
Not too sure about fading, but when you leave a state, you could save a bitmap and alpha it away to 0 over a certain amount of time.
In answer to your question about calling each others render, you could do it a bit like I described above, with "GetBaseState()->Render()" style, or simple have the state objects call a third object to do the rendering - after all, you are going to need a "GameData" object separate from any of your states. ie, "gGameData->DrawMap()", thereby not doubling up on your drawing code
IMHO, states should be self-contained and not have to worry about what other states may or may not be present. That can get complicated surprisingly quickly, apart from ideological arguments.

I agree with Telastyn's idea of having a transition class which manages a fade (or, indeed, any other transition).

For a state stack, I think the onus is on the stack to render each state in order. A dialogue-box state should only render itself, leaving whatever was there before still visible outside it's own window space. Something like (C#):
Stack states;void RenderStates(){ for(int i = 0; i < states.Count; i++)  (states as State).Render();}

This topic is closed to new replies.

Advertisement