implementing state machines with the engine?

    This site uses cookies. By continuing to browse this site, you are agreeing to our Cookie Policy.

    • implementing state machines with the engine?

      How would I use the architecture in the book to create an awareness of game states e.g various game menus, and different game levels? I may have a lot of menus, where the game should exit that menu state with the option that the user selected, and then do logic depending on what the user chose, so I wouldn't want to hard code it. It'll be ideal if I could extend this to work with xml definitions or script logic.

      Based on my research, a state machine looks to be the way to go, but i'm not sure how I could fit this into the architecture especially when it comes with processes. Would each menu or level be a process?
    • I'd need to know a little more about what you're trying to accomplish. I would implement game menus and game levels in different ways. It also depends on what kind of game level you're looking for and how you want it to effect the game.

      I'll start with game levels.

      The way I approach this is by having different resource packages, one for each level plus a global one that is always available. When I ask for an asset, my resource system searches the level-specific package first, then the global one. This has the side effect of allowing me to override assets if I want.

      When a level is loaded, I also load the scripts along with it. One of those scripts will spin up the various script objects I need to run the game. As entities are loaded, their script representations will be loaded as well. Any necessary processes are create, event listeners are registered, etc. Then I run the Lua garbage collector, let the resource thread finish loaded, drop the loading screen, and I'm in the game.

      So for me, a level isn't really a state inside a state machine, it's a whole resource package with all the side effects that entails. It works really well, though I don't quite have a good solution for the tear-down of a level on the script side. The entities all get destroyed, but I keep having to watch the script state to make sure I destroy all the extra systems that spin up from the level without destroying the truly global systems, though there are very few of those in my engine.

      As for game menus, what are you trying to do? Are you talking about the main menu, options menus, credits, etc? Can you give me a better picture as to what you want?

      -Rez
    • Levels are for an fps-style game. I really like your idea of having them as resource packages as that fits into the data-driven design philosophy.

      One type of menus would be things like the main menu, options menu, credits, "choose a save slot" etc. Another type may be menus that could appear in the level itself i.e choosing an action from a list of choices. Some menus will be exited immediately if a choice is made, while for other menus, the user would explicitly have to activate a confirm/cancel button after selecting all desired options.

      It'd be ideal if the menus could be loaded from text files, as that may become very useful in other games like rpgs or strategy games.

      The post was edited 1 time, last by Neurone ().

    • This all depends on your GUI system. My GUI system works like this:

      All gui elements inherit from a base Widget class. Widgets form a tree structure, so any widget can have any number of children, which in turn can have children of their own. There is always a root widget that serves as the root of the entire tree. Widgets have a bunch of layering code to handle things like being able to click on a child and passing that click down to the deepest appropriate child.

      Widget hierarchies are defined in data. In my case, I use Lua tables as my core data format rather than XML (it was an experiment I tried which has mostly been successful) so all of my GUI hierarchy definitions are defined as nested Lua tables. Here's an example I copied & pasted right out of a project I created a couple years ago:

      Brainfuck Source Code

      1. -----------------------------------------------------------------------------------------------------------------------
      2. -- HUD
      3. -----------------------------------------------------------------------------------------------------------------------
      4. local hud =
      5. {
      6. x = 0, y = 0, w = GetScreenWidth(), h = GetScreenHeight(),
      7. type = "Window",
      8. children =
      9. {
      10. Clock =
      11. {
      12. x = 1, y = GetScreenHeight() - 32, w = 165, h = 32,
      13. type = "TexturedWindow",
      14. texture = "textures/UI/black.dds",
      15. children =
      16. {
      17. ClockText =
      18. {
      19. type = "StaticText",
      20. font = "fonts/TestFont.bft",
      21. text = "WWW 00:00pm",
      22. },
      23. },
      24. },
      25. ActionDisplay =
      26. {
      27. x = GetScreenWidth() - 300, y = GetScreenHeight() - 32, w = 300, h = 32,
      28. type = "TexturedWindow",
      29. texture = "textures/UI/black.dds",
      30. children =
      31. {
      32. ActionDisplayText =
      33. {
      34. type = "StaticText",
      35. font = "fonts/TestFont.bft",
      36. text = "Thinking...",
      37. },
      38. },
      39. },
      40. },
      41. };
      Display All


      Once I'm ready to push this, I just call a function to push the entire hierarchy.

      So back to your problem of wanting a main menu, I would probably create each of the menus (options, load game, etc.) as a separate hierarchy like this. For larger games, I actually create factory methods in Lua so I can just generate stuff as needed. For example, if I have a particular style of button I like, I might write a function that returns a table representing the button data I want, taking in only the parameters I care about (probably just text and callback). This is one of the cool advantages to using Lua as my data format, though I've done similar things in the past with XML.

      Using a state machine here would be fine but honestly, creating all this architecture for what will probably just be two states seems excessive. If it were me, I'd just push the main menu hierarchy, set the new input mode, and pause the game. Then I'd reverse all that when the main menu was done.

      If you're hell-bent on using a state machine or you think you're going to have a lot of states, here's how I'd do it. First, I'd write a generic state machine system that can be used anywhere. State machines are generic constructs; don't waste time building something super-specific when something generic will work just as well. You can reuse this in different places (animation, AI, etc.) Anyway, it would roughly look like this:

      Source Code

      1. class State
      2. {
      3. public:
      4. virtual ~State() { }
      5. virtual void EnterState() = 0;
      6. virtual void Update() = 0; // sometimes I don't include update.... it depends on what I'm trying to do
      7. virtual void ExitState() = 0;
      8. };
      9. class StateMachine
      10. {
      11. State* m_pCurrState;
      12. public:
      13. StateMachine();
      14. ~StateMachine();
      15. void SetState(State* pNewState);
      16. void Update();
      17. };
      18. StateMachine::StateMachine()
      19. : m_pCurrState(nullptr)
      20. {
      21. //
      22. }
      23. StateMachine::~StateMachine()
      24. {
      25. delete m_pCurrState;
      26. }
      27. void StateMachine::SetState(State* pNewState)
      28. {
      29. // Note: Another way to handle this function is to have it take in an enum value instead
      30. // of a state. The advantage there is that you don't have to expose state class, but it
      31. // does make it a little more annoying because each state machine has to be coupled
      32. // with a factory to generate the concrete State classes. Unless you have a real need to
      33. // do it another way, I'd stick with something like this.
      34. // exit and destroy the current state
      35. if (m_pCurrState)
      36. {
      37. m_pCurrState->ExitState();
      38. delete m_pCurrState;
      39. }
      40. // set the new state; note that this transfers ownership
      41. m_pCurrState = pNewState;
      42. // if we're setting a new state, enter it
      43. if (m_pCurrState)
      44. m_pCurrState->EnterState();
      45. }
      46. void StateMachine::Update()
      47. {
      48. if (m_pCurrState)
      49. m_pCurrState->Update();
      50. }
      Display All


      I just wrote this all free-hand, so I'm sure there are issues with it. For example, State::Update() probably should return a State* so that it can return a new state if necessary. It should probably also pass in a deltaTime variable.

      Anyway, then you'd have a state machine instance inside of Logic or possibly your game app depending on how you set up the interface between Application, Logic, and View. Inside Logic::Update() (or GameApp::Update()) you'd just call the state machine update. You'd create specific states for each game state, like in-game, main menu, etc.

      Make sense?

      -Rez
    • The UI i'm creating would need to be represented as states.

      So the app layer reads OS events. It keeps track of the game's current state; possible states (which are UI-specific things) are states in a state machine. Its also supposed to translate the OS events into commands sent to the game logic.
      If you were in some menu, I wanted the menu to "swallow" the OS events and prevent it from also being translated into commands sent to game logic. The best I've came up with was the following:

      1. App layer reads events from the OS. It knows the current state.
      2. curState->update() is run, which processes OS messages first, then decide whether they should be forwarded to other views.
      ...

      Would it be better to do this state processing from the human view instead? I think I may be a bit confused on the role of the human view.

      The post was edited 1 time, last by Neurone ().