Loading the menu state from an XML file

We now have most of our state loading code in place and can make use of this in the MenuState class. First we must do a little legwork and set up a new way of assigning the callbacks to our MenuButton objects, since this is not something we could pass in from an XML file. The approach we will take is to give any object that wants to make use of a callback an attribute named callbackID in the XML file. Other objects do not need this value and LoaderParams will use the default value of 0. The MenuButton class will make use of this value and pull it from its LoaderParams, like so:

void MenuButton::load(const LoaderParams *pParams)
{
  SDLGameObject::load(pParams);
  m_callbackID = pParams->getCallbackID();
  m_currentFrame = MOUSE_OUT;
}

The MenuButton class will also need two other functions, one to set the callback function and another to return its callback ID:

void setCallback(void(*callback)()) { m_callback = callback;}
int getCallbackID() { return m_callbackID; }

Next we must create a function to set callbacks. Any state that uses objects with callbacks will need an implementation of this function. The most likely states to have callbacks are menu states, so we will rename our MenuState class to MainMenuState and make MenuState an abstract class that extends from GameState. The class will declare a function that sets the callbacks for any items that need it and it will also have a vector of the Callback objects as a member; this will be used within the setCallbacks function for each state.

class MenuState : public GameState
{
  protected:

  typedef void(*Callback)();
  virtual void setCallbacks(const std::vector<Callback>& callbacks) 
  = 0;

  std::vector<Callback> m_callbacks;
};

The MainMenuState class (previously MenuState) will now derive from this MenuState class.

#include "MenuState.h"
#include "GameObject.h"

class MainMenuState : public MenuState
{
  public:

  virtual void update();
  virtual void render();

  virtual bool onEnter(); 
  virtual bool onExit(); 

  virtual std::string getStateID() const { return s_menuID; }

  private:

  virtual void setCallbacks(const std::vector<Callback>& 
  callbacks);

  // call back functions for menu items
  static void s_menuToPlay();
  static void s_exitFromMenu();

  static const std::string s_menuID;

  std::vector<GameObject*> m_gameObjects;
};

Because MainMenuState now derives from MenuState, it must of course declare and define the setCallbacks function. We are now ready to use our state parsing to load the MainMenuState class. Our onEnter function will now look like this:

bool MainMenuState::onEnter()
{
  // parse the state
  StateParser stateParser;
  stateParser.parseState("test.xml", s_menuID, &m_gameObjects, 
  &m_textureIDList);

  m_callbacks.push_back(0); //pushback 0 callbackID start from 1
  m_callbacks.push_back(s_menuToPlay);
  m_callbacks.push_back(s_exitFromMenu);

  // set the callbacks for menu items
  setCallbacks(m_callbacks);

  std::cout << "entering MenuState
";
  return true;
}

We create a state parser and then use it to parse the current state. We push any callbacks into the m_callbacks array inherited from MenuState. Now we need to define the setCallbacks function:

void MainMenuState::setCallbacks(const std::vector<Callback>& 
callbacks)
{
  // go through the game objects
  for(int i = 0; i < m_gameObjects.size(); i++)
  {
    // if they are of type MenuButton then assign a callback 
    based on the id passed in from the file
    if(dynamic_cast<MenuButton*>(m_gameObjects[i]))
    {
      MenuButton* pButton = 
      dynamic_cast<MenuButton*>(m_gameObjects[i]);
      pButton->setCallback(callbacks[pButton->getCallbackID()]);
    }
  }
}

We use dynamic_cast to check whether the object is a MenuButton type; if it is then we do the actual cast and then use the objects callbackID as the index into the callbacks vector and assign the correct function. While this method of assigning callbacks could be seen as not very extendable and could possibly be better implemented, it does have a redeeming feature; it allows us to keep our callbacks inside the state they will need to be called from. This means that we won't need a huge header file with all of the callbacks in.

One last alteration we need is to add a list of texture IDs to each state so that we can clear all of the textures that were loaded for that state. Open up GameState.h and we will add a protected variable.

protected:
std::vector<std::string> m_textureIDList;

We will pass this into the state parser in onEnter and then we can clear any used textures in the onExit function of each state, like so:

// clear the texture manager
for(int i = 0; i < m_textureIDList.size(); i++)
{
  TheTextureManager::Instance()->
  clearFromTextureMap(m_textureIDList[i]);
}

Before we start running the game we need to register our MenuButton type with the GameObjectFactory. Open up Game.cpp and in the Game::init function we can register the type.

TheGameObjectFactory::Instance()->registerType("MenuButton", new MenuButtonCreator());

We can now run the game and see our fully data-driven MainMenuState.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.21.93.20