简体   繁体   中英

Is this Polymorphism and is this bad practice?

I'm setting up a State system for my game.

class State
{
protected:
 enum State_
 {
     STATE_INTRO,
     STATE_GAME,
     STATE_PAUSE,
     STATE_CUTSCENE,
 };
public:
 State();
 virtual void run(State_) = 0;
 virtual ~State(); // virtual destructor cus we will be inheriting this class
};

I then have inherited classes which represent each state

class IntroState : public State
{

public:
    void run(State_ STATE);
};

I want the run function to have different functionality based off of what state the game is in, is it bad practice to achieve that like this:

void IntroState::run(State_ STATE)
{
    if (STATE == STATE_INTRO)
    {
        // load the intro
    }
}

I'm not sure how else to do this, thanks (and keep in my mind I'm JUST learning about states so I might be completely off here)

I think you don't need polymorphism in your case since you will only have one State class in your application (correct me if I'm wrong).

You're run function would look like this:

void run(State_ state)
{
  switch (state)
  {
    case STATE_INTRO:
      doIntro();
    case STATE_BLAH:
      doBlah();
    // fill all you states...
  }
}

void doIntro()
{
  // do something for the intro
}

void doBlah()
{
  // do something for blah
}

Now if you really wanna get fancy and remove the switch statement:

class State
{
    private:
        void doA() {}
        void doB() {}

        enum State_
        {
            A = 0,
            B,
            END_
        };

        std::function<void(void)> functions[END_];

    public:
        State()
        {
            functions[A] = std::bind(&State::doA, this);
            functions[B] = std::bind(&State::doB, this);
        }

        void run(State_ state)
        {
            functions[state]();
        }
};

To expand on my comment, here is a possible approach (improvements are appreciated):

class Game {
  //... Initialize all State-derived classes in constructor and put them in states (not shown)
  vector<unique_ptr>> states;
  State_ currentState {STATE_INTRO};
  State_ nextState {STATE_INTRO};
  public:
    void setNextState(State_ state ) {nextState = state;}
    void Play() { 
      for(;;) { //endless loop
        if (!states[currentState]->run()) return;//stopping when run returns false
        currentState = nextState;
      }
    }
};

And run could look like this:

class IntroState : public State {
  //... 
  void run(Game& game) {
    // do stuff
    game.setNextState(STATE_GAME);
    return true;
  }
};

Of course, you need to figure out the include order, and you'll need to forward-declare Game in State.hpp (the code shown here only shows the central idea). Also, the implementations of run and Play should of course be in seperate.cpp files (didn't do that here so this example wouldn't get too long)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM