Putting it all together

We can now put all of this knowledge together and implement as much as we can into our framework, with reusability in mind. We have quite a bit of work to do, so let's start with our abstract base class, GameObject. We are going to strip out anything SDL-specific so that we can reuse this class in other SDL projects if needed. Here is our stripped down GameObject abstract base class:

class GameObject
{
public:

  virtual void draw()=0;
  virtual void update()=0;
  virtual void clean()=0;

protected:

  GameObject(const LoaderParams* pParams) {}
  virtual ~GameObject() {}
};

The pure virtual functions have been created, forcing any derived classes to also declare and implement them. There is also now no load function; the reason for this is that we don't want to have to create a new load function for each new project. We can be pretty sure that we will need different values when loading our objects for different games. The approach we will take here is to create a new class called LoaderParams and pass that into the constructor of our objects.

LoaderParams is simply a class that takes values into its constructor and sets them as member variables that can then be accessed to set the initial values of an object. While it may just seem that we are moving the parameters from the load function to somewhere else, it is a lot easier to just create a new LoaderParams class than to track down and alter the load function of all of our objects.

So here is our LoaderParams class:

class LoaderParams
{
public:

  LoaderParams(int x, int y, int width, int height, std::string 
  textureID) : m_x(x), m_y(y), m_width(width), m_height(height), 
  m_textureID(textureID)
  {

  }

  int getX() const { return m_x; }
  int getY() const { return m_y; }
  int getWidth() const { return m_width; }
  int getHeight() const { return m_height; }
  std::string getTextureID() const { return m_textureID; }

private:

  int m_x;
  int m_y;

  int m_width;
  int m_height;

  std::string m_textureID;
};

This class holds any values we need when creating our object exactly the same way as our load function used to do.

We have also removed the SDL_Renderer parameter from the draw function. We will instead make our Game class a singleton, such as TextureManager. So, we can add the following to our Game class:

// create the public instance function
static Game* Instance()
{
  if(s_pInstance == 0)
  {
    s_pInstance = new Game();
    return s_pInstance;
  }

  return s_pInstance;
}
// make the constructor private
private:

  Game();
// create the s_pInstance member variable
  static Game* s_pInstance;

// create the typedef
  typedef Game TheGame;

In the Game.cpp, we have to define our static instance:

Game* Game::s_pInstance = 0;

Let's also create a function in the header file that will return our SDL_Renderer object:

SDL_Renderer* getRenderer() const { return m_pRenderer; }

Now that Game is a singleton, we are going to use it differently in our main.cpp file:

int main(int argc, char* argv[])
{
  std::cout << "game init attempt...
";
  if(TheGame::Instance()->init("Chapter 1", 100, 100, 640, 480, 
  false))
  {
    std::cout << "game init success!
";
    while(TheGame::Instance()->running())
    {
      TheGame::Instance()->handleEvents();
      TheGame::Instance()->update();
      TheGame::Instance()->render();

      SDL_Delay(10);
    }
  }
  else
  {
    std::cout << "game init failure - " << SDL_GetError() << "
";
    return -1;
  }

  std::cout << "game closing...
";
  TheGame::Instance()->clean();

  return 0;
}

Now when we want to access the m_pRenderer value from Game, we can use the getRenderer function. Now that GameObject is essentially empty, how do we achieve the code-sharing we originally had? We are going to derive a new generic class from GameObject and call it SDLGameObject:

class SDLGameObject : public GameObject
{
public:

  SDLGameObject(const LoaderParams* pParams);

  virtual void draw();
  virtual void update();
  virtual void clean();

protected:

  int m_x;
  int m_y;

  int m_width;
  int m_height;

  int m_currentRow;
  int m_currentFrame;

  std::string m_textureID;
};

With this class we can create our reusable SDL code. First, we can use our new LoaderParams class to set our member variables:

SDLGameObject::SDLGameObject(const LoaderParams* pParams) : 
GameObject(pParams)
{
  m_x = pParams->getX();
  m_y = pParams->getY();
  m_width = pParams->getWidth();
  m_height = pParams->getHeight();
  m_textureID = pParams->getTextureID();

  m_currentRow = 1;
  m_currentFrame = 1;
}

We can also use the same draw function as before, making use of our singleton Game class to get the renderer we want:

void SDLGameObject::draw()
{
  TextureManager::Instance()->drawFrame(m_textureID, m_x, m_y, 
  m_width, m_height, m_currentRow, m_currentFrame, 
  TheGame::Instance()->getRenderer());
}

Player and Enemy can now inherit from SDLGameObject:

class Player : public SDLGameObject
{
public:

  Player(const LoaderParams* pParams);

  virtual void draw();
  virtual void update();
  virtual void clean();
};
// Enemy class
class Enemy : public SDLGameObject
{
public:

  Enemy(const LoaderParams* pParams);

  virtual void draw();
  virtual void update();
  virtual void clean();
};

The Player class can be defined like so (the Enemy class is very similar):

Player::Player(const LoaderParams* pParams) : 
SDLGameObject(pParams)
{

}

void Player::draw()
{
  SDLGameObject::draw(); // we now use SDLGameObject
}

void Player::update()
{
  m_x -= 1;
  m_currentFrame = int(((SDL_GetTicks() / 100) % 6));
}

void Player::clean()
{
}

Now that everything is in place, we can go ahead and create the objects in our Game class and see everything in action. We won't add the objects to the header file this time; we will use a shortcut and build our objects in one line in the init function:

m_gameObjects.push_back(new Player(new LoaderParams(100, 100, 128, 82, "animate")));

m_gameObjects.push_back(new Enemy(new LoaderParams(300, 300, 128, 82, "animate")));

Build the project. We now have everything in place to allow us to easily reuse our Game and GameObject classes.

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

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