Skip to content

Silva StateMachine

Mattis DALLEAU edited this page Jun 8, 2022 · 1 revision

Silva (StateMachine)

The StateMachine

A state machine is a class that is used to manage the state of the game.

It is generally used to avoid big conditional branchings

Your first state

class MyState : public State {
public:
    MyState()
    {
        std::cout << "Hello World!" << std::endl;
    }

    ~MyState()
    {
        std::cout << "Goodbye World!" << std::endl;
    }

    void update() override {
        std::cout << "Update" << std::endl;
    }
};

int main()
{
    StateMachine stateMachine;
    stateMachine.changeState<MyState>();
    stateMachine.update();
    stateMachine.update();
}

Expected output:

Init
Update
Update
Goodbye World

Your first stacked state!

When to use a stacked state?

Imagine your are in game and you want to pause it.

You don't want to destroy the current state.

So you create a new state and push it to the stack.

Here is the example:

class GameState : public State {

    void update() override {
        std::cout << "Playing" << std::endl;

        if (KeyboardPressed(KEY_ESCAPE)) {
            stateMachine.pushState<PauseState>();
        }

        player.update();
    }

};

class PauseState : public State {

    void update() override {
        std::cout << "Paused" << std::endl;

        if (KeyboardPressed(KEY_ESCAPE)) {
            stateMachine.popState();
        }

        buttons.update();
    }

};

This example should make use alternatively the GameState and PauseState classes.

Behaviours with StateMachine:

class RunBehaviour : public State {
private:
    Player& player;

public:
    RunBehaviour(Player& animable) : player(player)
    {
    }

    void update() override {
        // Specific update code

        if (player.notMoving()) {
            player.changeState<IdleBehaviour>(player);
            return;
        }
    }
};

class IdleBehaviour : public State {
private:
    Player& player;

public:
    IdleBehaviour(Player& player) : player(player)
    {
    }

    void update() override {
        // Specific update code
        if (player.isMoving()) {
            player.changeState<RunBehaviour>(player);
            return;
        }
    }
};

class ActionBehaviour : public State {
private:
    Player& player;

public:
    ActionBehaviour(Player& player) : player(player)
    {
    }

    void update() override {
        // Specific update code

        if (player.finishedAction()) {
            player.changeState<IdleBehaviour>(player);
            return;
        }
    }
};

class Player {
private:
    Animable animable;
    StateMachine stateMachine;
    Vector2 velocity;

public:
    Player() { stateMachine.changeState<IdleBehaviour>(player); }

    void update() { stateMachine.update(); }

    bool isMoving() const { return velocity.x != 0 || velocity.y != 0; }

    bool notMoving() const { return !isMoving(); }

    template<typename T>
    void changeState(Player& player) { stateMachine.changeState<T>(player); }
};