William Barnes William Barnes - 3 months ago 9
C++ Question

C++ States: Sequence of Events is not very object orientated

I am struggling to make my code more object orientated.

I have a small program that wishes to accomplish 2 very simple states: An input state, and a result state.

The input state seems simple to resolve as although it is graphical it is "self-updating." The user drops sprites and removes sprites on to the screen to produce an input.

The result state is annoying me because I have produced some very ugly code for it, that is not at all Object Orientated.

This state is required to do things sequentially and I am struggling to find examples of how that is done with Objects. It's basically some animation with the same object: here is some Pseudo-Code.

Static int objectx = 120, object y = 120;
Static int state=0

switch(state)
{
Case 0:
//....move object right
//....once object is far enough right
state = 1;

Case 1:
//....move object down
//....once object is far enough down
state = 2;

...etc


So I am guessing it needs to move to having some sort of state engine, but I am struggling to see how to accomplish sequential events using states. These states are always the same, and so can be hard coded, they will not change based upon the input given.

Any help will be most gratefully recieved.

UPDATE

Maybe we could think about this second state as a cut-scene in a 2d game. We want a character to walk on to the screen, say something and then walk off.

So the way I'm doing it at the moment is managing this part of the programs state via the switch statement. This function is called every time we are in the "result" part of our program, and we are using the switch statement to update the positions of our sprites. Once we have reached the end of the first set of movements we move to the next switch statement and keep doing that until it is completed. It works but I was hoping to use a " gamestate " Class, that could take ownership of the graphics and sound, and move things as appropriate.

Answer

Note: making some assumptions here because I don't have any context.

It sounds like each sprite should have its own cycle, rather than the entire game logic moving about the sprites. Adapting this into an object-orientated design, you can wrap each sprite in some class:

class NPC : Sprite {
    private:
        Position CurrentPosition;
        int CurrentState;

    public:
        virtual void Think() = 0;
        virtual void Render() = 0;
};

Then you can inherit from this class for specific sprites:

class GobbledyGook : NPC {
    private:
        const int FinalState = 10;

    public:        
        bool Completed = false;

        void Think() override {
            if(Completed)
                return;

            switch(CurrentState) {
                // ... repeating logic here ...
            }

            CurrentState++;

            if(CurrentState == FinalState)
                Completed = true;
        }

        void Render() override {
            // ... draw the sprite ...
        }
}

From the main game logic you can then update every sprite:

// Spawn a GobbledyGook into existence.
my_npcs.insert(new GobbledyGook());

// In frame logic.
bool finished = true;
for( NPC* n : my_npcs )
{
    n->Think();
    if(!n->Completed)
        finished = false;
}

if(finished) {
    // Result state.
}

// In render logic.
for( NPC* n : my_npcs )
{
    n->Render();
}

You can naturally adopt this logic for entire scenes too:

class Intro : Cutscene {
    private:
        vector<NPC*> SceneSprites;

    public:
        void Think() override {
            switch(CurrentState) {
                ...
            }

            for( NPC* n : SceneSprites ) {
                n->Think();
            }
        }

        ...
};

As for whether you should be removing or changing the use of states, what do you intend to gain from doing that?

It's hard to recommend a different approach without knowing all the flaws of the current approach.