Finite State Machine/ State Pattern

I've been trying to make my first game but I'm having trouble just setting up the basic game states. I don't want to use enum's and switch statements so I'm hoping to use a finite state machine to switch between screens but every article iv read about them is different and sometimes they leave out details, i'm just not understanding exactly how it works.

Say for example i had three screens. The Main Menu screen, In-Game screen and Pause screen. What would a finite state machine look like to switch between them? I don't mean for someone to write code for me, just maybe pseudo code or even an explanation.

Any help would really be much appreciated.

Last edited on
In a state machine, all the possible conditions that the AI or program can be running are stored in some sort of data structure. When you need to be running these elements, you iterate to the specific position which would run that aspect of the system. For example, lets theorize that each mode that you postulated in the question is a collection of vertices and methods that would essentially run a game, but it is not specific as to what it is actually running. Lets call this class cState. There are three cStates: Main Menu, the in-Game screen, and the pause screen. Each one has its own collection of stuff that it utilizes to render each aspect that is unique to each state.
1
2
3
4
5
6
7
8
9
10
11
class cState{};

//... before the main loop

cState States[3];
int CurrentState = 0;   //start at the menu screen

//... in the main loop

//running the main game
States[CurrentState].run();


but if the user presses "escape", you would change the States position to 2, because the user wants to pause the game:

1
2
if(Input.key == Input::Key::Escape)
  CurrentState = 2;  //move into the pause screen 


Since c++ uses inheritance and run-time polymorphism, it is easy to implement a state machine by making cState a pure virtual base class, and having on member: Run(). If you had a game object, and that object inherits from cState, its simple to utilize this logic:

1
2
3
4
5
6
7
8
9
10
11
12
13
class cState
{
public:  
      virtual void Run() = 0;
};

class cGame : public cState
{
public:
    //override the Run function    
    void Run()
    { //do stuff};
};


Does this make sense?

Thank you for the response. One problem i have with that, and that i have had myself when trying to implement a FSM, is that "CurrentState = 2" seems a bit ambiguous. I plan to have quite a few states and eventually its might be hard to know which state is which, and even harder for someone else to read.

The way i've been trying is by storing a pointer to each state in a vector, each state has a pointer to the state machine so it can change the current state. There's a few thing i don't understand like how does the state machine know which state to change to and which state it is changing from.

These could probably be solved by enumerations and switches, or even assigning strings to each state and then iterating through them comparing strings. But i thought the point of a state machine was so you didn't have to do that.
> how does the state machine know which state to change to and which state it is changing from.

That information should be encapsulated in each state. Each state knows about its behaviour; what it does in response to an event, and what state it must transition to.

A trivialized example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#include <iostream>
#include <vector>

struct game ;

struct game_state
{
    virtual ~game_state() ;

    // handle key down event, return state after event
    virtual game_state* on_key_down( char key, game& g ) = 0 ;

    virtual const char* name() const = 0 ;
};

game_state::~game_state() {}

struct state_zero : game_state
{
    virtual const char* name() const override { return "#0" ; }
    virtual game_state* on_key_down( char key, game& g ) override ;
    /* ... */
};

struct state_one : game_state
{
    virtual const char* name() const override { return "#1" ; }
    virtual game_state* on_key_down( char key, game& g ) override ;
    /* ... */
};

struct state_two : game_state
{
    virtual const char* name() const override { return "#2" ; }
    virtual game_state* on_key_down( char key, game& g ) override ;
    /* ... */
};

struct game
{
    int score() const { return current_score ; }
    int add_to_score( int v ) { return current_score += v ; }

    void on_key_down( char key )
    {
        current_state = current_state->on_key_down( key, *this ) ;
        std::cout << "    on key: " << key << "   state: " << current_state->name() << '\n' ;
    }

    // accessors elided for brevity
    static std::vector< game_state* > states ;

    private:
        int current_score ;
        game_state* current_state = states[0] ;
};

std::vector< game_state* > game::states = { new state_zero, new state_one, new state_two } ;

game_state* state_zero::on_key_down( char key, game& g )
{
    std::cout << "state_zero::on_key_down\n" ;

    if( key == '0' ) // no state transition
        { g.add_to_score(10) ; return this ; }
    else return g.states[1] ; // transit to state 1
}

game_state* state_one::on_key_down( char key, game& g )
{
    std::cout << "state_one::on_key_down\n" ;

    if( key == '1' ) // no state transition
        { g.add_to_score(20) ; return this ; }
    else return g.states[2] ; // transit to state 2
}

game_state* state_two::on_key_down( char key, game& g )
{
    std::cout << "state_two::on_key_down\n" ;

    if( key == '2' ) // no state transition
        { g.add_to_score(30) ; return this ; }
    else return g.states[0] ; // transit to state 0
}

int main()
{
    game g ;
    char c ;
    while( std::cin >> c ) g.on_key_down(c) ;
}




> These could probably be solved by enumerations and switches,
> or even assigning strings to each state and then iterating through them

If there are many states, using per-state state-transition-tables are typical.
considergoogleing scene graph.

http://en.wikipedia.org/wiki/Scene_graph
Topic archived. No new replies allowed.