2

A game is a set of Game States.

Each Game State contains game objects, may be list, may be scene graph or any other data structure.

We can use Game States as Game Locations, too.

How do you share data between Game States, for example, hero and his/her inventory when it moves from one location to another?

It looks like Composite (hierarchical) Game State is a good idea. For example,

GameState MainMenu
GameState LoadLevel
GameState Gameplay - contains inner states
    GameState Location1
    GameState Location2
    GameState Location3
    GameState MiniGame1 - contains inner states
        GameState LocationInMiniGame1
        GameState LocationInMiniGame2

So we can hold shared data (hero, inventory) in Gameplay object. But this approach does not look very correct and flexible. If some objects are outside scene graph (ie in the parent Game State), how would you include it in the scene graph? Via special node type that mounts different scene graphs or scene graph branches together?

If we have stack of active Game States, and each state can contain inner state machine, and scene graphs of different Game States can be mounted into one giant graph, it can become very complex system that is hard to debug.

Very interesting to read your suggestions. How do you organize game data between Game States in your real applications?

(For editors: possible additional tags: OOP, game-state.)

Bálint
  • 14,887
  • 2
  • 34
  • 55
topright
  • 1,300
  • 1
  • 14
  • 22

3 Answers3

9

My suggestion is to not have game states like this whatsoever. Most of your essential game objects exist across and outside of all the states (eg. renderer, resource loading, input, networking, audio), and a massive amount of the rest span multiple states (eg. players, some NPCs, certain resources).

On top of that, the stack system doesn't seem to work well in practice. What if I want to bring up an options menu from within the mini-game - how is that going to differ from bringing it up from the main menu? What if I can quit the whole game from within the mini-game?

I'd ask, what value does this big state system give you? If you need to know what location you're in, store a location object or variable. If you're on the main menu, your GUI object will have a menu panel up; otherwise, it won't. Maybe there's an argument for pushing a new state when you enter a mini-game or cut-scene but I don't think I'd even do it then.

So my answer to "how do you share data between same States" is to not have game states at all.

Kylotan
  • 24,329
  • 3
  • 51
  • 94
  • I can't downvote Ricket's longwinded defense of global variables or upvote this answer enough. –  Sep 28 '10 at 15:02
  • Thank you, sounds radically, but interesting. Stack of active states can be used to render all states and update only the topmost. PauseState on the top of the stack lets you render GamePlayState, too, but to stop updating it. GUI doesn't allow this. Hierarchy of states lets you share data between game states without having global variables. – topright Sep 28 '10 at 15:13
  • So your Location object contains scene graph and you mount somehow shared objects (hero, inventory etc.) into it? – topright Sep 28 '10 at 15:15
  • 1
    @Pavel: you can do that sort of thing with a single game loop, an 'is_paused' flag, and a GUI. eg. bind the Escape key to { pauseGame(); showMenu(); } and when you close the menu, call { unpauseGame(); hideMenu(); } There are no more globals needed in this case than the state stack case - you essentially just have 1 game state instead of several. – Kylotan Sep 28 '10 at 15:50
  • @Pavel: As for rendering, scene graph' can mean a variety of things but it doesn't have to live within a Location at all. You build the scene graph out of the data in the current location, maybe at load time, maybe dynamically. (Personally I'm not convinced traditional scene graphs are a great idea anyway but it's up to you.) – Kylotan Sep 28 '10 at 15:53
  • 1
    @Kylotan: How do you implement mini-games without states? Different modes of gameplay (exploring, combat etc.)? If you have many hierarchical submenus, it is not enough to have a showMenu() function. May be I'm wrong, but I think your code will become spaghetti code, if you do not use Game States in these cases. – topright Sep 28 '10 at 19:13
  • 1
    Wow. The games I've worked on with state stacks were the ones with the fewest (i.e. zero) state transition bugs. I'm not sure how Joe W thinks that this post isn't about global variables, either. – dash-tom-bang Sep 28 '10 at 21:53
  • @dash-tom-bang: I'd encourage you to weigh in at http://gamedev.stackexchange.com/questions/1783/ - while I do still agree with everything I wrote there, I think there is a lot more to be said in defense of state systems that is also not there. In terms of sharing data, I strongly prefer to think about resource ownership and object lifetimes, and not global state variables. In that sense, I agree with Kylotan's answer - sharing data should be managed through zero states. Some systems must manage state within that system - that's not for data sharing, but their own encapsulated computation. –  Sep 28 '10 at 23:06
  • @Joe- have done, thanks. Spent way too much time but waiting for a build so I can rationalize... – dash-tom-bang Sep 29 '10 at 00:30
  • @Pavel: it's not that I don't think you'd ever have states at all, but that rather than having this vague concept of a State which can mean anything from loading to menus to different gameplay types, you limit it to the stuff that really matters, and use it where needed, not as containers for the whole game. If you have different gameplay at some point, then maybe you have 2 different objects that encapsulate gameplay state and switch between them - but they don't own substates, or live on a stack, or any of that. – Kylotan Sep 29 '10 at 10:00
  • @dash-tom-bang: I can't help but feel that the stack is just a hack that people use with game states once they realise that certain things must outlive individual states - so they push it up the stack. However I'm not completely against the use of states, as long as they refer to homogeneous objects, reflect truly different types of interaction, and aren't just dumping grounds for pseudo-globals. – Kylotan Sep 29 '10 at 10:04
  • @Pavel: oh, and on the menus - that's a property of the menu object. You don't need to store anything outside the menu to remember which part of the menu you're on, if your GUI is adequate. Ideally you should be able to pop up any menu at any time, without necessarily pausing the game (think about multiplayer). – Kylotan Sep 29 '10 at 10:08
  • @Kytolan I agree with the overengineering worry; in C and C++ I implement states as enum values and switch statements; turning these into "rich objects" definitely has a negative impact on browsability, comprehensibility, and execution speed. On the other hand, in Python I implemented them as modules/objects that I threw on the stack, and it worked out well enough since enums and switches are ahem less convenient in Python. :) – dash-tom-bang Sep 30 '10 at 19:10
  • 1
    Game states are a logical refactoring of this answer's proposed "big messy loop with lots of flags and switch statements". I'd like to know some concrete examples of games that shove everything into a single game loop method with no concept of state objects. And as for "global variables", there's no difference, can't you see? - my suggestion is to have some variables shared by several states; this answer suggests all the states together in one loop, with shared variables. Absolutely no difference right? Or you can use Singletons (AKA global variables). – Ricket Sep 30 '10 at 20:46
  • @Ricket, why are you quoting "big messy loop" when nobody else has said that? The loop doesn't have to be big, but neither does it have to be completely devoid of any sort of stateful objects. However, I would argue that these objects should not be abstract 'gamestates' which attempt to cover menus, loading, different levels, etc. Most of that can be covered by more specific state (eg. menu should be part of the GUI, locations are a property of the world or the current map, etc.) – Kylotan Oct 01 '10 at 10:13
  • I was (mis)using them for emphasis I guess, sorry. But quotation marks do not always mean a direct quote from someone else, there are other uses for quotation marks. At this point we are arguing about abstract things and it's going nowhere. Again I would like to see some actual game source code which does this, as I could clearly learn from it. Your description doesn't give me a clear sense of it though. – Ricket Oct 01 '10 at 12:12
6

The concept of state stacks is very valuable and very useful in games. One particular game in my memory had the major states of "main menu", "playing a movie", "in game", and "in-game menu", with a centralized place that handled transitioning between these things. It was great because you could push a ton of crap at once and end up where you wanted to be without guessing. E.g. at startup "main menu" is pushed, then "movie" (gamelogo) then another "movie" (dev logo) then a third movie (pub logo).

Then the in-game had a ton of state, and that state was per-level. In this case it didn't make sense to make it a stack, since only one could be active at a time and the endlevel code would take care of transitioning to the next level (after pushing the load/save UI which in this case was part of the main menu).

Each level will likely have a ton of "areas" or sublevels or whatever. There is stuff that exists only in an area (e.g. the monsters), but there is the stuff that transcends the sublevels and is more appropriately "owned" by the level itself or even the in-game state "object". (The game I'm recalling had different player "costumes" in different levels, so it made sense to attach that to the level. Other games might just load a single player model and use it for the life of the in-game state.)

Some states do have sub-states though. These aren't polluting the "main" state stack, these are internal state stacks. E.g. the in-game menu will have a page stack like Ricket discusses so that "back" works uniformly. The memory card handling may be another separate stack too since it runs asynchronous to the rest of the UI.

In short, put data where it makes the most sense to you, and don't hesitate to move it if another home becomes preferable.

dash-tom-bang
  • 1,666
  • 9
  • 11
-1

I started learning programming from web development. My first steps were opening notepad, writing some HTML, saving it, and opening it in a browser. Then I wrote another HTML file and saved it. And then I made a link. Suddenly I had two pages which I could go back and forth between.

Then I got into PHP; I could handle user input! I could even save data about an user. I used cookies or the session to save data about the user between pages.

Now just a few months ago, as I was thinking and wondering the same question as you, I realized game states are like PHP pages. They're very discrete, each one being a different view of your application (game, in this case), but they need some shared data. They need session data.

Well, in PHP, to store something in the session you just use $_SESSION['variablename']='value';. Then you can later retrieve that data, from any PHP page visited by the same user in the same session, by referring to $_SESSION['variablename'];. Essentially, it's a global array, and in PHP you can easily add values to an array so it's essentially equivalent to a Map.

So if you want to go this route, then add a "global" Map which acts as your "session" data. This will hold all of the data that needs to be shared between game states. Or simply make it a "global" object and add all the variables you need; this is entirely up to you, based on your needs. (obviously an object will get much better performance than a Map) - when I say "global", I mean make it available to all of your game states. You shouldn't make it available to any other objects which don't need it. This can be done, for example, by a variable inside the gamestate namespace, or a package-private Singleton in a language like Java.

Note this is only one way to do it. I really kind of like the way you want to attach the data to the parent Gameplay object; but in my state system I didn't really account for sub-states so I was just thinking of the PHP way.

Ricket
  • 14,810
  • 6
  • 66
  • 82
  • Interesting answer, thank you. I have PHP background, too, so you just hit the bull's eye. :) – topright Sep 28 '10 at 14:07
  • Globally available, globally mutable state is almost always the wrong solution. – dash-tom-bang Sep 30 '10 at 19:11
  • Okay then let's say you write a multiplayer game. The main menu establishes a network connection, stored in some sort of network connection variable, and then starts the game state. How does the game state get access to that network connection without shared data? – Ricket Sep 30 '10 at 20:36
  • 2
    Shared data does not mean global data. Pass what you need, don't pass what you don't, and don't access anything you aren't passed. (That's the ideal at least.) –  Oct 01 '10 at 00:07
  • Static variables in the local compilation unit or package-private singletons in Java are still "globals" when it comes to reasoning about program execution. You're accessing stuff you aren't passed; you're forced to reason about a much larger part of the program. –  Oct 01 '10 at 15:26