Jimmyt1988
Jimmyt1988

Reputation: 21136

Snookered myself with class inheritance, need some guidance

I have a Player class... He needs access to components inside PlayerStateFlying and PlayerStateHit classes so I inherited from them...

class PlayerStateFlying
{
    // Includes a function that sets Player::currentState = something
}

class PlayerStateHit
{
    // Includes a function that sets Player::currentState = something
}

class Player : public PlayerStateFlying,
               public PlayerStateHit
{
    public:
        STATE currentState; // Needs to be accessed by the State classes
}

Problem is, my State classes need access to one of Player's properties

How do I go about solving this problem?

---------EDIT-----------

So should it be something like this? P.S I can't quite get it to work

class IBaseStates
{
    public:
        STATE currentState;
}

class PlayerStateFlying : public IBaseStates
{
    // Includes a function that sets IBaseStates::currentState = something
}

class PlayerStateHit : public IBaseStates
{
    // Includes a function that sets IBaseStates::currentState = something
}

class Player : public IBaseStates
{
    // Includes a function that checks what IBaseStates::currentState equals
}

Here is an example of my dilemma:

void Player::ChangeState( STATE state )
{
    switch( state )
    {
    case FLYING:
        currentState = FLYING;
        break;
    case HIT:
        currentState = HIT;
        break;
    }
}

void Player::StateUpdate()
{
    switch( currentState )
    {
    case FLYING:
        PlayerStateFlying::Update( );
        currentTextureIndex = PlayerStateFlying::current;
        break;
    case HIT:
        PlayerStateHit::Update( );
        currentTextureIndex = PlayerStateHit::current;
        break;
    }
}

void PlayerStateHit::Update( )
{
    ...
            currentState = FLYING;
            index = 0;
    ...    
}

Upvotes: 0

Views: 90

Answers (3)

Konrad Talik
Konrad Talik

Reputation: 916

Do not forget about polymorphism. You don't need to implement any switch'es.

I think the solution should look like:

class PlayerState {
}

class PlayerStateFlying : public PlayerState {
}

class PlayerStateHit : public PlayerState {
}

Now your Player class (object) should contain (or access) a state object:

class Player {
protected:
    PlayerState *playerState;
public:
    void setPlayerState(PlayerState *newState);
}

setPlayerState() should look like:

Player::setPlayerState(PlayerState *newState) {
    playerState = newState;
}

Now you can simply rewrite your methods for the future supporting variety of PlayerState subclasses:

void Player::StateUpdate() {
    playerState->Update(); // Polymorphism!
    currentTextureIndex = playerState->current;
}

In the next method you can still use a switch if you still really need to store your currentState variable and use it:

void Player::ChangeState( STATE state ) {
    switch( state ) {
    case FLYING:
        currentState = FLYING;
        playerState = new PlayerStateFlying();
        break;
    case HIT:
        currentState = HIT;
        playerState = new PlayerStateHit();
        break;
    }
}

... but there is another -- more convenient solution -- setPlayerState -- we already have it, but if we still need currentState enum (or int or whatever) variable, we can simply expand our PlayerState class (and subclasses) with a new field -- label:

class PlayerState {
public:
    int label;
}

PlayerStateFlying::PlayerStateFlying() {
    label = FLYING;
}

PlayerStateHit::PlayerStateHit() {
    label = HIT;
}

Now it is possible to:

Player::setPlayerState(PlayerState *newState) {
    playerState = newState;
    currentState = playerState->label;
}

You can also try with constant fields, that is:

class PlayerState {
public:
    const int label;
}

PlayerStateFlying::PlayerStateFlying() : label(FLYING) {};

PlayerStateHit::PlayerStateHit() : label(HIT) {};

Regards.

Upvotes: 2

Gasim
Gasim

Reputation: 7961

A player should be the one setting what the current state is. Not the state itself. And the state update function should look something like:

void Player::StateUpdate() {
    mCurrentState->update(this);
}

void PlayerHitState(Player * player) {
    player->setCurrentState(player->getStateFromListOfAvailableStates(FLYING))
}

A simple state machine should store all the needed states and transitions. Like you can't fly if you are in water or something similar.

Upvotes: 1

Steve Barnes
Steve Barnes

Reputation: 28390

Have a common class that stores the State and the information that is needed access to and inherit from it in both Player states.

Upvotes: 0

Related Questions