Skip to content

State Machine

joshlengel edited this page Jul 2, 2020 · 8 revisions

State Machine

As described in the Design page, the state machine is the heart of the game engine. Every piece of client code must be executed in a state. The structure of the state machine will be presented below:

_______________                          ______________     _____________
|             |                          |            |     |           |
| Start state |  ---- RequestExit() ---> | Next state | ... | End state |
|_____________|                          |____________|     |___________|

OnStateEntered:

The client can save a reference to the previous state's resource by retrieving them from the StateEnteredEvent.

OnStateUpdated:

The client can perform updating and input operations like camera movement and keyboard input.

OnStateRendered:

The client can render the models in the state

OnStateExited:

Caused by the main window closing or a call to RequestExit() in the previously mentioned functions, the client can add or remove any resources to or from the set received in the OnStateEntered function. Additionally, the client can specify which state should be transitioned to by calling Infinity::StateExitedEvent::SetNextState</name of next state/>().


Given the above structure the following is an example of some client code using the state system:

class EndState;

class StartState : public Infinity::State
{
private:
    Infinity::Resource<Infinity::Model> m_model;

public:
    void OnStateEntered(Infinity::StateEnteredEvent &event)
    {
        m_model = Infinity::Model::CreateModel(1);

        // Initialize model
    }

    void OnStateUpdated(Infinity::StateUpdatedEvent &event) override { /* perform updating */ }
    void OnStateRendered(Infinity::StateRenderedEvent &event) override { /* perform rendering */ }

    void OnStateExited(Infinity::StateExitedEvent &event) override
    {
        // Pass m_model to next state
        auto &resources = event.GetResources();
        resources["model"] = m_model;

        // Tell the state machine to transition to EndState
        event.SetNextState<EndState>();
    }
};

class EndState : public Infinity::State
{
private:
    Infinity::Resource<Infinity::Model> m_model;

public:
    void OnStateEntered(Infinity::StateEnteredEvent &event)
    {
        // Retrieve m_model from last state
        auto &resources = event.GetResources();
        m_model = resources["model"].Get<Infinity::Model>();
    }

    void OnStateUpdated(Infinity::StateUpdatedEvent &event) override { /* perform updating */ }
    void OnStateRendered(Infinity::StateRenderedEvent &event) override { /* perform rendering */ }

    void OnStateExited(Infinity::StateExitedEvent &event) override
    {
        // Don't set next state to terminate
    }
};

// Tell Infinity which state to start with
void Infinity::SetClientStartState()
{
    Infinity::SetStartState<StartState>(); // Don't try to initialize StartState yourself
}

Infinity::State subclasses must have default constructors! If this is not the case, Infinity::SetStartState will fail.


The code above does not separate the class definitions into .h and .cpp files. To simplify the declarations of these four functions, Infinity defines a macro to declare them for you:

// StartState.h

class StartState : public Infinity::State
{
public:
    DECLARE_STATE_EVENT_FUNCTIONS() // Declares OnStateEntered, OnStateUpdated, OnStateRendered and OnStateExited
};

Clone this wiki locally