I've been working on a small game as a hobby, and I've been having trouble finding a good way to control the state of the game that could scale easily. I couldn't find a solution that I felt was correct, so I wrote my own. I created an abstract base class State that has an abstract function update that takes and returns a pointer to the State base class. All children of State's update function should check if conditions are met to change the State if so it should delete the current state, and return another child of State. If it shouldn't transition states it update its data members and return the current state for the next pass in the loop.I'm not a very experienced C++ programmer, and I feel I'm in over my head. I came to this solution by myself, and even though it work correctly and appears like it will scale fine in the future I'm worried if I went about this wrong or if there are safer or more efficient ways to deal with this problem. Looking back at my code I'm surprised I can delete a pointer of a class inside one of its own functions. Also the update method by design is completely unsafe which could be trouble.I cut the state machine out of my project, and made a simple model of how it could be used, with two example states.main.cpp#include State.h#include State1.hint main() {    State* state = new State1();    //Main loop, how state updates itself.    while (state->isRunning()) {        state = state->update(state);    }    return 0;}State.hclass State {public:    State();    virtual ~State();    //Very unsafe method to update data in the main loop and change state.    //Up to programmer to not mess things up.    virtual State* update(State* currentState) = 0;    //getter for running    bool isRunning() const;protected:    static bool running;};State has a static variable running to keep track of when it should quit the main loop, like when the user closes the window. I felt a static variable was fine here since there should only ever be one state at a time.State.cpp#include State.hbool State::running = true;State::State() {}bool State::isRunning() const{    return running;}State::~State() {}State1.h#include State.hclass State1 : public State {public:    State1();    ~State1();    State* update(State* currentState);private:    int dataMember;    int* dataMemberThatNeedsToBeDeleted;};State1.cpp Here State2 requires an int to be constructed. One advantage I found with this model is that states can easily share data between each other when transitioning. For instance if I was building a fighting game and it was currently on a character select state it could share the characters the players chose with the fighting state and that state could construct the characters to fight in that scene, and when one player wins it can share data like k/d ratio and winner with the score state. States also are responsible to delete all memory allocated.#include State1.h#include State2.h#include <iostream>State1::State1() : dataMember(50), dataMemberThatNeedsToBeDeleted(new int(30)) {    std::cout << creating state1! << std::endl;}State *State1::update(State *currentState) {    std::cout << State1's first data member is:  << dataMember << std::endl;    std::cout << State1's other data member is:  << *dataMemberThatNeedsToBeDeleted << std::endl;    std::cout << std::endl;    delete currentState;    return new State2(dataMember);    //In the actual code it would use if/switch statements to control the flow    //example if this state was talking to an inputManager:    //         if (key.pressed = esc) {    //             running =  false;    //             return currentState;    //         } else if (key.pressed = i) {    //             delete currentState;    //             return new InventoryState(playerCharacter);    //         } else    //             return currentState;}State1::~State1() {    delete dataMemberThatNeedsToBeDeleted;}State2.h#include State.hclass State2 : public State {public:    State2(int _dataMember);    ~State2();    State* update(State* currentState);private:    int dataMember;};State2.cpp#include State2.h#include iostreamState2::State2(int _dataMember) : dataMember(_dataMember) {    std::cout << creating state2! << std::endl;}State *State2::update(State *currentState) {    std::cout << State2's data member is  << dataMember << std::endl;    std::cout << std::endl;    running = false;    return currentState;}State2::~State2() {}And I get the correct output of:creating state1!State1's first data member is: 50State1's other data member is: 30creating state2!State2's data member is 50
Solving game state with polymorphism
c++;state machine