Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length

 
Advanced search

880032 Posts in 33018 Topics- by 24385 Members - Latest Member: jhewitt

May 25, 2013, 03:39:20 PM
TIGSource ForumsDeveloperTechnical (Moderators: Glaiel-Gamer, ThemsAllTook)Switching Game States
Pages: [1] 2
Print
Author Topic: Switching Game States  (Read 663 times)
paste
Level 6
*


BARF!

HeyIAintEddie
View Profile WWW
« on: April 08, 2012, 01:14:17 AM »

Most games that I've made so far have a few main state classes (think Intro, MainMenu, Gameplay) but I think the way I've handled them is kind of sloppy. Basically, what I would do is have an exposed variable in the state (e.g. GoingToMenu inside the Intro class) and the overarching Game class would switch between these. Of course, the type and behavior of these variables vary a lot from state to state, so the Game class is highly connected to all of the states. I was wondering if anyone had some cleaner solutions to this kind of issue.

I was thinking of making a base class that the state classes can derive from and possibly using callbacks to the Game class somehow. However, I don't want to reinvent the wheel if there's a perfectly good way of handling this already. Any ideas?
Logged

Cironian
Level 0
**


View Profile
« Reply #1 on: April 08, 2012, 02:35:56 AM »

I do this by having all states derived from a GameMode base class, which is the only thing the main game loop knows about.

That one has calls to render one frame, grab input and so on. It also has a getNewMode function which returns a fully set up mode object when it is switching time (or null if we want to keep the current mode for now).

That way, the class that actually wants to switch to a new mode and has the necessary information can create the new mode object and then call setNewMode on the current GameMode. The main loop then grabs that at the end of the current frame and works with it from the next frame on.
Logged

Solar War - Turn-based space strategy
BorisTheBrave
Level 10
*****


View Profile WWW
« Reply #2 on: April 08, 2012, 04:21:26 AM »

I'm pretty similar. I general have a bunch of Screen objects, arranged in a stack by the ScreenManager. The top-most Screen object is active, the others suspended. Sometimes I have a concept of "transparent" screens, which means that screens below it still get calls to Draw(), but not to Step(), so they are paused. The menu screen is pushed in main, and it is responsible for constructing and pushing the game screen, which is responsible for constructing and pushing cutscenes, pause menus, etc.

I find it's not helpful to view different screens/modes as states of a state machine. You typically need to pass more info than just the type of screen, and the information to be passed is highly specific to the particular transition.
Logged
sublinimal
Level 6
*


This game is: UNPLAYABLE


View Profile
« Reply #3 on: April 08, 2012, 07:31:43 AM »

The concept is that I have nested state functions, each returning an integer. If one of them returns 0, everything returns 0 and the program quits. Otherwise we just fall back to the previous one.

Code: (Relevant portion)
def play():
    
    # function pointers accessed by list indexes - cleaner than 'if' statements
    states = [exit, single_player, options, intro]        # exit() always returns 0
    
    # executes the function in 'states' with the index returned by main_menu()
    return states[main_menu()]()        # main_menu() draws the main menu and returns a selection number

intro()
while play():   # main loop
    pass

print 'Thanks for playing!'

It fits my Pythonic way of thinking. Use management classes if you need to share data back and forth between game states (but the point is to minimize that).

Edit: Bah, I got stuck in an endless post-tweaking loop again.
« Last Edit: April 08, 2012, 07:46:31 AM by sublinimal » Logged

Megaproject: Panacea
Big project: that other game
Control Room is dead, long live Veins of a Planet
Latest jam game: Vineyard Adagio (LD26)
Xienen
Level 2
**


Greater Good Games


View Profile WWW Email
« Reply #4 on: April 08, 2012, 07:54:52 AM »

I laid out the Break Blocks engine with the concept of Game States with each being a derivation of some base class.  So I had class GameState, which defined the Init/Update/Draw/Shutdown functions, and a series of sub classes for Intro, Menu, and Game.  After working with that and the annoying issues that pop up with handling the flow between classes, I've decided that I want a state transition handler.  So I'll still have the same state classes to encapsulate the code, but rather than just having a "CurrentState" pointer, I'll have a state handler object that looks at the state we're in(and optionally the one we're transitioning to) to determine which GameState functions to call.  The idea is that I can just call, for example, GameStateTransitionHandler.GotoMenu(MenuName) and if I'm currently in the Game Class, it will do the proper initialization of the Menu GameState, as well as handle any in between transition I'd like, such as a loading screen.  If, however, I'm already in the Menu GameState, it could perform a separate set of operations, if needed.  I haven't tried this new method yet, but it seems like it'll be an improvement.
Logged

Owner/Programmer at Greater Good Games makers of Break Blocks
Currently developing It Hungers(Unity) and Swipe Attack(UDK)
rivon
Level 10
*****



View Profile
« Reply #5 on: April 08, 2012, 08:08:10 AM »

In my last "game" I had an abstract base class Screen with run() function which I subclassed to create MainMenuScreen, GameScreen etc... MainMenuScreen was created at the beginning, it's run() method was called and then the menu, for example when selecting New Game, created a GameScreen passing the name of the first level as an argument and then calling the GameScreen's run() method. That way, every screen returns back to the previous one.
« Last Edit: April 08, 2012, 09:09:06 AM by rivon » Logged
Average Software
Level 10
*****

Fleeing all W'rkncacnter


View Profile WWW Email
« Reply #6 on: April 08, 2012, 08:46:24 AM »

I have an abstract state type called Logic that all of my states inherit from.  The most important part of Logic is an operation called Process which executes one frame of logic and returns a pointer to the next state.  Most of the time, the active Logic just returns itself, it only returns something else if I'm transitioning.  Every frame, the main loop compares the new state to the previous state and frees the old one if they've changed.

This is the relevant section of my main loop:

Code:
declare
    Next_State: Logic_Access;
begin
    -- Process the logic, obtaining the next logic.
    Current_State.Process(Next_State);

    -- If the logic has changed...
    if Next_State /= Current_State then
        -- Release the old logic.
        Free(Current_State);
        -- Store the new one.
        Current_State := Next_State;

        -- A state of null is a request to die.
        if Current_State = null then
            return 0;
        end if;
    end if;
end;
Logged

Franchise - The restaurant wars begin!

What would John Carmack do?
paste
Level 6
*


BARF!

HeyIAintEddie
View Profile WWW
« Reply #7 on: April 08, 2012, 08:55:01 AM »

Thanks guys.

I'm probably overthinking this next thing (and I probably won't implement it, since it's time to shit or get off the pot), but could you imagine any scenario where one would have to be running two or more states simultaneously? Like if i wanted to do a cross-fade between two states?
Logged

Xienen
Level 2
**


Greater Good Games


View Profile WWW Email
« Reply #8 on: April 08, 2012, 08:56:59 AM »

In my last "game" I had an abstract base class Screen with run() function which I subclassed to create MainMenuScreen, GameScreen etc... MainMenuScreen was created at the beginning, it's run() method was called and then the menu, for example when selecting New Game, created a GameScreen passing the name of the first level as an argument an and then calling the GameScreen's run() method. That way, every screen returns back to the previous one.

Ah, pretty good idea.  I have debated a State Stack before, particularly for menu navigation.  I hadn't really thought about using it for all game states. I wonder, though, if it could properly handle this sequence: Intro->Main Menu->Sub Menu->Game->Main Menu
Basically, the Intro should be removed from the stack when going to the Main Menu, as it'll never be needed again.  Then, if I have an option to return to the Main Menu from the game, it'd have to be sure to pop off the correct number of Sub Menus.  Is there an elegant solution for these issues that I'm just not thinking of?
Logged

Owner/Programmer at Greater Good Games makers of Break Blocks
Currently developing It Hungers(Unity) and Swipe Attack(UDK)
Xienen
Level 2
**


Greater Good Games


View Profile WWW Email
« Reply #9 on: April 08, 2012, 09:00:45 AM »

Thanks guys.

I'm probably overthinking this next thing (and I probably won't implement it, since it's time to shit or get off the pot), but could you imagine any scenario where one would have to be running two or more states simultaneously? Like if i wanted to do a cross-fade between two states?

Perhaps if you're doing a fade/slide/etc transition from the Intro to the Main Menu?  The same could be true for transitioning from a Menu to a Loading screen...and a Loading screen into the game.  Really just depends on if you'd like to do a visual transition or just pop from one to the next.

Another possibility, though, would be to render one or both Game States to a texture and use that to perform the visual transition.
Logged

Owner/Programmer at Greater Good Games makers of Break Blocks
Currently developing It Hungers(Unity) and Swipe Attack(UDK)
BorisTheBrave
Level 10
*****


View Profile WWW
« Reply #10 on: April 08, 2012, 09:01:50 AM »

could you imagine any scenario where one would have to be running two or more states simultaneously? Like if i wanted to do a cross-fade between two states?
It seems most people (myself included), code support for multiple states directly into the managing function if they need that sort of functionality.

But seeing as nearly everyone is using classes to represent each state, you could imagine a TransitionState that owns two children state. and makes use of both, eventually yielding control to one of them. Would work particularly well with Average's "return the next state" method.
Logged
paste
Level 6
*


BARF!

HeyIAintEddie
View Profile WWW
« Reply #11 on: April 08, 2012, 09:07:39 AM »

Perhaps if you're doing a fade/slide/etc transition from the Intro to the Main Menu?  The same could be true for transitioning from a Menu to a Loading screen...and a Loading screen into the game.  Really just depends on if you'd like to do a visual transition or just pop from one to the next.

Another possibility, though, would be to render one or both Game States to a texture and use that to perform the visual transition.

I was considering rendering the exiting state to a texture and using that for some transition effect. It wouldn't be as dynamic as possible, but all of this stuff could probably be implemented in a separate iteration or something.
« Last Edit: April 08, 2012, 09:24:58 AM by paste » Logged

rivon
Level 10
*****



View Profile
« Reply #12 on: April 08, 2012, 09:28:47 AM »

Ah, pretty good idea.  I have debated a State Stack before, particularly for menu navigation.  I hadn't really thought about using it for all game states. I wonder, though, if it could properly handle this sequence: Intro->Main Menu->Sub Menu->Game->Main Menu
Basically, the Intro should be removed from the stack when going to the Main Menu, as it'll never be needed again.  Then, if I have an option to return to the Main Menu from the game, it'd have to be sure to pop off the correct number of Sub Menus.  Is there an elegant solution for these issues that I'm just not thinking of?

Simplified pseudocode:
Code:
main()
{
initGraphics();

IntroScreen* is = new IntroScreen;
is->run(); // doesn't create any more screens and just returns after the end of the intro
delete is;

MainMenuScreen* mms = new MainMenuScreen;
mms->run();
delete mms;

destroyGraphics();
}

MainMenuScreen::run()
{
while(running)
{
processEvents();

if (NEW_GAME_SELECTED)
{
GameScreen* gs = new GameScreen("level-1");
gs->run();
delete gs;
}
else if (LOAD_GAME_SELECTED)
{
SelectLoadScreen* sls = new SelectLoadScreen();
sls->run(); // after selecting which game to load, creates GameScreen, then returns
delete sls;
}
else if (OPTIONS_SELECTED)
{
OptionsScreen* os = new OptionsScreen("level-1");

// it might create another screen for every submenu like OptionsAudioScreen, OptionsControlsScreen, etc.
// or it might just draw a specific options part according to some variable like currentOptionsMenu which
// could be OPTIONS, CONTROLS, AUDIO, GRAPHICS etc.
os->run();
delete os;
}
else if (...)
{
...
}
else if (QUIT_SELECTED)
{
running = false;
}

drawMenu();
}

return;
}
Logged
Xienen
Level 2
**


Greater Good Games


View Profile WWW Email
« Reply #13 on: April 08, 2012, 10:17:01 AM »

Interesting rivon.  Looks like it could definitely be made to work in just about any situation...
* Xienen ponders
Logged

Owner/Programmer at Greater Good Games makers of Break Blocks
Currently developing It Hungers(Unity) and Swipe Attack(UDK)
rivon
Level 10
*****



View Profile
« Reply #14 on: April 08, 2012, 10:30:45 AM »

The only thing which isn't so easy with this approach are the transitions between screens but there are many ways how it can be solved.
Logged
Pages: [1] 2
Print
Jump to:  

Theme orange-lt created by panic