2

I don't know if my question title makes sense, so apologies in advance for that. so... I'm trying to implement a state machine for a little game I'm trying to make using C++ and SFML.

I have a GameLoopObject abstract class which needs a renderwindow argument and has these virtual methods: update, draw, handleinput and reset.

Then I have a GameState abstract class which inherits from GameLoopObject, but doesnt add anything new yet so its basically the same as GameLoopObject, for now.

Last, I have a GameStateManager class which also inherits from GameLoopObject and should handle my gamestates.

Now my problem is that I want to use a GameState currentState and a nextState member variable in my GameStateManager, but I can't seem to find the correct way/syntax to declare these and use them afterwards. I'd prefer leaving them empty (if that's possible in C++), as GameState objects are being stored inside of them immediately after making a GameStateManager object.

Basically, what I'm trying to do is something along the lines of this:

GameStateManager(sf::RenderWindow & w) : 
    GameLoopObject(w), 
    currentState(new GameState(w)), 
    nextState(new GameState(w));

Which gives me a "no default constructor exists for class "GameLoopObject" "

This is the rest of my code:

/*
 * GameStateManager.hpp
 */

#ifndef GameStateManager_HPP
#define GameStateManager_HPP

#include "stdafx.h"
#include "GameLoopObject.hpp"
#include "GameState.hpp"
#include<string>
#include<map>

class GameStateManager : GameLoopObject {
private:
    GameState currentState;
    GameState nextState;
public:
    std::map<std::string, GameState> gameStates{}; // list where all known gamestates are stored.

    // methods
    GameStateManager(sf::RenderWindow & w);

    void AddGameState(std::string name, GameState * state);
    void SetNext(std::string name);
    void SwitchState();
    void HandleInput(); 
    void Update();
    void Draw();
    void Reset();
};

#endif //GameStateManager_HPP



/*
 * GameStateManager.cpp
 */
#include "stdafx.h"
#include "GameStateManager.hpp"

GameStateManager::GameStateManager(sf::RenderWindow & w)
// : GameLoopObject(w)
{
    GameState currentState(w);
    GameState nextState(w);
}

void GameStateManager::AddGameState(std::string name, GameState * state)
{
    gameStates.insert(std::make_pair(name, * state));
}

void GameStateManager::SetNext(std::string name)
{
    //check if user wants to exit (close window with X)
    if (gameStates.count(name))
    {
        nextState = gameStates[name];
    }
}

void GameStateManager::SwitchState()
{
    if (currentState != nextState)
    {
        currentState = nextState;
    }

}

void GameStateManager::HandleInput()
{
    // if(currentState != null)
    currentState.HandleInput();
}

void GameStateManager::Update()
{
    // if(currentState != null)
    currentState.Update();
}

void GameStateManager::Draw()
{
    // if(currentState != null)
    currentState.Draw();
}

void GameStateManager::Reset()
{
    // if(currentState != null)
    currentState.Reset();
}
Simson
  • 3,373
  • 2
  • 24
  • 38
Caedendi
  • 37
  • 6
  • You can't declare an instance of an abstract class, use a pointer instead, or better yet a smart pointer. – nitronoid Jan 18 '18 at 01:11
  • thx for commenting nitronoid:) so if i want to make an instance of a "gamestate" (which at the moment is abstract) and afterwards, inside that object, i want to store an actual, non-abstract gamestate (like MainMenuState), will that work with a (smart) pointer, or should i do that another way? – Caedendi Jan 18 '18 at 01:15
  • The problem is that you can never make an instance of an abstract class. However you can use an Abstract class pointer, to point to any of the derived classes and access it's virtual interface. – nitronoid Jan 18 '18 at 01:23

1 Answers1

1

I see you have two issues here, both stemming from the fact that you can't declare an instance of an abstract class. The members of the class should be GameState pointers. You also face the same issue when you call new GameState, there is no constructor available here as GameState is abstract.

I'm not sure whether your GameStateManager is the owner of the current and next state. In the case that it is, you should change the type of your members to std::unique_ptr<GameState>, otherwise just use a GameState*.

Your constructor doesn't need to create a new GameState object to initialise these members if they don't own the states, in this case you would pass a pointer to an existing GameState. However if they do, you must call new ConcreteGameState where ConcreteGameState is some derived class of GameState that is not abstract.

EDIT: Looking at your member functions, you almost definitely want to a raw pointer.

EDIT 2: Noticed you are currently privately inheriting from GameLoopObject, you should change that to public by adding the keyword:

class GameStateManager: public GameLoopObject
nitronoid
  • 1,459
  • 11
  • 26
  • thanks a lot! i think i have solved most of the issues that the code has given me. the only error left is "no default constructor exists for class "GameLoopObject" " in the GameStateManager.cpp constructor body. any ideas? – Caedendi Jan 18 '18 at 01:39
  • If you are still writing `currentState(new GameState(w))` you should remove this. – nitronoid Jan 18 '18 at 01:50
  • i have removed that. the problem i am facing now is that when making the GameState * currentState, nextState pointers, i get the "no appropriate default constructor available" error because my gamestate constructor asks for a &window parameter – Caedendi Jan 18 '18 at 02:03
  • i have eventually solved my last problem by removing the parameter requirement in the GameLoopObject and GameState abstract classes and only asking for a parameter (&window) when implementing an actual gamestate (f.i., MainMenuState(sf::referencewindow &window) ). – Caedendi Jan 18 '18 at 05:06
  • thanks a lot nitronoid! thank you so friggin much for helping. without, i wouldve been stuck for another 10 hours not knowing what to do and what actually went wrong. – Caedendi Jan 18 '18 at 05:07