Jump to content

  • Log In with Google      Sign In   
  • Create Account

FREE SOFTWARE GIVEAWAY

We have 4 x Pro Licences (valued at $59 each) for 2d modular animation software Spriter to give away in this Thursday's GDNet Direct email newsletter.


Read more in this forum topic or make sure you're signed up (from the right-hand sidebar on the homepage) and read Thursday's newsletter to get in the running!


Questions about state driven games


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
12 replies to this topic

#1 Norman Barrows   Crossbones+   -  Reputation: 2349

Like
0Likes
Like

Posted 28 August 2013 - 12:58 PM

Questions about state driven games:

 

by "state driven" i mean something like a pong clone with states like "titlescreen", "mainmenu", and "rungame".

 

IE one loop that displays output and processes input based on the current "game state".

 

while that might be all fine and good for pong,   what happens when you get dozens or hundreds of states?  

 

 

state driven seems to take the hierarchical call structure of a game and "flatten it out" into a bunch of "states" at the same level.

 

IE:

 

 

void rungame

while ! quitgame

    renderall

    process_input

    updateall

 

 

 

void runprog

// do main menu

// if select new game

     {

     initgame

     rungame

     endgame

     }

// if select load game

     {

     initgame

     loadgame

     rungame

     endgame

     }

 

 

 

void main

initprog

titlescreen

runprog

endprog

 

 

becomes states like:

 

uninitialized

titlescreen

mainmenu

load game dialog

rungame

 

 

which means you'd have a state for the in-game menu, and each stats screen, and so on.....  correct?

 

 

 

 

 


Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

 

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

 

 


Sponsor:

#2 Servant of the Lord   Crossbones+   -  Reputation: 21183

Like
3Likes
Like

Posted 28 August 2013 - 01:32 PM

Why do they need to be flattened on the same "level"?

Who says gamestates can't have children?

And why can't you run more than one gamestate at once?

Why can't gamestates have their own state machine as well?

 

And, uh, why would you even have an "uninitialized" state? blink.png


Edited by Servant of the Lord, 28 August 2013 - 06:07 PM.

It's perfectly fine to abbreviate my username to 'Servant' rather than copy+pasting it all the time.
All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.
Of Stranger Flames - [indie turn-based rpg set in a para-historical French colony] | Indie RPG development journal

[Fly with me on Twitter] [Google+] [My broken website]

[Need web hosting? I personally like A Small Orange]


#3 Kryzon   Prime Members   -  Reputation: 3314

Like
0Likes
Like

Posted 28 August 2013 - 02:20 PM

I still think states should be kept as horizontal as possible.
For me it's easier to understand when the priority between states is dictated by their position on a stack rather than a hierarchical relationship. "Only the top-most state is executed, period". The rest are waiting for their turn.
 

// if select new game
     {
     initgame
     rungame
     endgame
     }
// if select load game
     {
     initgame
     loadgame
     rungame
     endgame
     }

 
It could be the following when under a different paradigm.
 

500px-Data_stack.svg.png

 

 

// Starting the game.
Program
    -> Sponsor_Screen.


// Entering the menu. The Sponsor_Screen state popped itself and pushed a Menu state on the stack.
// This pair of operations can be called a 'change'.
Program
    -> Menu.


// Changing options and displaying an option screen, a state pushed on top of Menu.
// It's on top of the Menu state because you want this screen to fall back to the menu gracefully.
Program
    -> Menu
        -> Options_Screen.


// Starting the game. The menu state 'changed' to a Start_Game state.
Program
    -> Start_Game.

 

Further reading: http://gamedevgeek.com/tutorials/managing-game-states-in-c/


Edited by Kryzon, 28 August 2013 - 02:35 PM.


#4 swiftcoder   Senior Moderators   -  Reputation: 10426

Like
2Likes
Like

Posted 28 August 2013 - 05:42 PM


And why can you run more than one gamestate at once?

QFE. A lot of people forget about this case when they try and design a state/screen system for their game.

 

What happens when you want to overlay your options menu on the game, but keep the game itself visible and running in the background?


Tristam MacDonald - Software Engineer @Amazon - [swiftcoding]


#5 ApochPiQ   Moderators   -  Reputation: 16414

Like
1Likes
Like

Posted 28 August 2013 - 05:45 PM

+1 for SotL and swiftcoder. Modal UI is poor design in many cases, so supporting multiple UI elements active concurrently is usually necessary for nontrivial games. What if Call of Duty made you press a button to pause the game and pull up your Current Health and Ammo menu?

#6 Norman Barrows   Crossbones+   -  Reputation: 2349

Like
0Likes
Like

Posted 28 August 2013 - 06:48 PM


Why do they need to be flattened on the same "level"?
Who says gamestates can't have children?

 

 

game states with sub states. ok, that makes more sense.

 


And why can't you run more than one gamestate at once?

 

don't quite follow you there....    you mean an overall state which is a combo of two or more sub states?

 

 


And, uh, why would you even have an "uninitialized" state? 

 

 

Don't ask me man....   It was in an example i saw!   <g>


Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

 

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

 

 


#7 Norman Barrows   Crossbones+   -  Reputation: 2349

Like
0Likes
Like

Posted 28 August 2013 - 06:59 PM

ok, now for the 64 dollar question:

 

except for things like HUD_on as a sub-state of render scene,

 

isn't a lot of the "control flow" of states already implicit in the call hierarchy of traditional code?

 

i do have places where i use something like a state variable to determine whether to render an indoor, outdoor, or underground scene, or whether or not to display a stats overlay on top of the normal game screen (HUD_on). but most things are handled automatically by call hierarchy.


Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

 

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

 

 


#8 AllEightUp   Moderators   -  Reputation: 4272

Like
0Likes
Like

Posted 28 August 2013 - 08:36 PM

Why do they need to be flattened on the same "level"?
Who says gamestates can't have children?


game states with sub states. ok, that makes more sense.
 

And why can't you run more than one gamestate at once?

 
don't quite follow you there....    you mean an overall state which is a combo of two or more sub states?


Another way to look at this is not to contain the state in the main loop at all. In my little tutorials project my entire state is controlled via the html/css+lua UI system (well, not completely there yet, working on it) which means for instance my splash screen is:

<rml>
 <head>
  <link type="text/css" href="Splash.rcss"/>
  <script>
   function RunSplashScreen()
    RegisterUpdate( 'SplashCountdown', 0,
     coroutine.wrap(
      function()
       ... Snip .... Basically three states:  FadeIn, Hold, FadeOut
       ... just written in a coroutine.
       UnregisterUpdate( 'SplashCountdown', 0 )
      end ) ) end
   </script>
 </head>
 <body onload="RunSplashScreen()"
       onunload="LoadDocument( 'UI/Menu.rml' ):Show( Document.Focused )"
  >
   <img id="Splash" src="Images/SplashScreen.png" align="middle" />
  </body>
</rml>
So, when I kick off the game, I load a startup script, which loads this. This does the splash screen, then finishes and loads the next item which is the menu. So you can think of those items as your rough 'big state' blocks. I can add/remove arbitrary items to be updated from the game loop once a frame or at certain intervals, so I can load in dialogs (both modal and nonmodal) etc, grab data from the engine to update with, or other various things even open up other OS windows for debug purposes whatever and do it all with a fairly nice little Lua script without futzing about with the main loop code.

So, getting to your description, I could have all of those different states encapsulated in these scripts and the game engine itself remains oblivious to such things and simply acts as a flow control system. Now, getting to object systems and such obviously gets a bit more complicated but that's another story. smile.png

#9 Kryzon   Prime Members   -  Reputation: 3314

Like
0Likes
Like

Posted 28 August 2013 - 09:14 PM

 

What happens when you want to overlay your options menu on the game, but keep the game itself visible and running in the background?

 

What if the game and the options screen both listen for the same keyboard input? If they are concurrent states, you would have behavior such as moving the cursor on the options screen and having the player character move in the background. You would have to make the game state be aware that there's an options screen state active, and so it should 'pause' or 'ignore' its input listener.

 

With a stack (and with an effort to keep states horizontal, equally important), the options screen can still update the animations, collisions etc. and render the background game (which is the same call to Engine.Update() and Engine.Render() etc. that the game state was performing), while taking input and only performing actions related to options, since its own input listener is the only active.

In other words, with a stack you can have an overlayed options screen with an active game running in the background.


Edited by Kryzon, 28 August 2013 - 09:19 PM.


#10 ApochPiQ   Moderators   -  Reputation: 16414

Like
0Likes
Like

Posted 28 August 2013 - 10:04 PM

Or you could implement a notion of focus like every GUI on earth has done for the past 40 years :-P

#11 Servant of the Lord   Crossbones+   -  Reputation: 21183

Like
2Likes
Like

Posted 28 August 2013 - 10:11 PM

 

And why can't you run more than one gamestate at once?

 
don't quite follow you there....    you mean an overall state which is a combo of two or more sub states?

 

If you have children states, then both the parent and the child are active at the same time. It's no longer StateA and StateB and StateC, but you have states of your game where StateA is running at the same time StateA1 and StateA2, but not StateA3 are running.

Example: In some games, when you stand still, your health and mana slide into view on the HUD.
So, you're walking around in the game world [State: Exploring]
Then conditionally, based on the data of the 'Exploring' state about whether the player is moving or not, it activates or deactivates one of its children: HealthHUD.
 

 

What happens when you want to overlay your options menu on the game, but keep the game itself visible and running in the background?

What if the game and the options screen both listen for the same keyboard input? If they are concurrent states, you would have behavior such as moving the cursor on the options screen and having the player character move in the background. You would have to make the game state be aware that there's an options screen state active, and so it should 'pause' or 'ignore' its input listener.

 


Here's how I do it:

whatever_parent.Push(InWorld) //Game world is displayed in this state (and animated).
InWorld.Push(Exploring) //Push to InWorld's private stack of children. Only the topmost child is active.
InWorld.Push(InGameMenu)

//Player can walk around, as well as the walking-around GUI gamestates can be children of this,
//like health bars and world mini-maps. Since this is drawn after 'InWorld', the world itself is drawn under whatever game elements.
InWorld.BringToTop(Exploring)

//Player can navigate the menu. Since this is drawn as a child of 'InWorld', the world itself is drawn under the menu.
InWorld.BringToTop(InGameMenu)

 
I use a stack together with parent-children. Each state can have it's own stack of children. Only the topmost child is active.
Each state can also have a collection of non-stacked children that are always active as long as the state itself is active. I'm not yet sure whether this is a good idea or not. I call these 'free children', as opposed to the 'stack children'.
The example at the beginning of this post, with the player's health and mana sliding into view, would be an example where I'd consider using a free-floating child rather than a stack child. Because the health and mana GUI widget doesn't have to have exclusive focus, and so doesn't have to take control away from, say, a mini-map widget.

With events, you want pass to the children first, so the most descended state gets priority to respond over ancestors.
With drawing, you draw first, so the most descended state gets to draw over the ancestors. ([Edit:] If using a 2D API with no depth buffer. With 3D, you want to draw in reverse order)

Actually, I have [DrawBefore, DrawAfter, UpdateBefore, UpdateAfter, ReactBefore, ReactAfter] overridable functions because sometimes you want finer control over it, if you actually do want a parent state to draw over the descendant state.
 
Here's my code:

void GameState::DoDrawing(sf::RenderTarget &renderTarget)
{
	//Activate, only if not yet activated already.
        //This makes sure that GameState::activated() gets called (but only once, until deactivated() gets called).
	this->activate();

	//Draw before the children.
	this->DrawBefore(renderTarget); //Virtual func, for derived classes

        //Draw all the free children, which are always active as long as this GameState is active.
	for(auto &object : this->pImpl->freeChildren)
		object->DoDrawing(renderTarget);

        //Draw the topmost stack child.
	if(this->pImpl->childStack.empty() == false)
		this->pImpl->childStack.back()->DoDrawing(renderTarget);

	//Draw after the children.
	this->DrawAfter(renderTarget); //Virtual func, for derived classes
}

DoUpdating() and DoReacting() are pretty much identical. I also have DoThinking(), because I'm seeing if separating my events (DoReacting) from my time-based updating (DoUpdating) and from my logic decisions (DoThinking()) works out well on my current project. As with free non-stack children, the votes still out on that. smile.png

 

This layout seems to be working for me so far - but since I haven't actually released my game yet, and it's still in semi-early development, you'll definitely want more experienced opinions before basing your solutions off of my experimentations.


Edited by Servant of the Lord, 28 August 2013 - 11:55 PM.

It's perfectly fine to abbreviate my username to 'Servant' rather than copy+pasting it all the time.
All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.
Of Stranger Flames - [indie turn-based rpg set in a para-historical French colony] | Indie RPG development journal

[Fly with me on Twitter] [Google+] [My broken website]

[Need web hosting? I personally like A Small Orange]


#12 Kryzon   Prime Members   -  Reputation: 3314

Like
0Likes
Like

Posted 28 August 2013 - 10:43 PM

Thanks for the clarification.



#13 Norman Barrows   Crossbones+   -  Reputation: 2349

Like
0Likes
Like

Posted 29 August 2013 - 07:31 PM

Other threads related to this thread:
 
 
 
 
 
 
 
 
 

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

 

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

 

 





Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS