1
\$\begingroup\$

I have a problem with designing classes for my game which I create.

In my app, there is:

  • the class CGame, which contains all the information about game, itself. For example, screen width, screen height, etc. In the main() function, I create a pointer to the CGame instance.
  • the class CGUIObject, which includes fields specifying its position and draw() method, which should be able to draw an object according to the screen size.
  • the class CGUIManager, which is a singleton, and includes a list of CGUIObjects. For each object, in a list, it calls the draw() method.

Now the problem is, each CGUIObject needs to know the screen size, which is held by CGame. However, I find it inefficient to include pointer to CGame instance in every object.


For clarity's sake, I'll provide some simple code:

class CGame
{  
   int screenWidth;
   int screenHeight;
};

class CGUIObject
{
   CPoint position;
   void draw();     // this one needs to know what is a screen's width and height
};

class CGUIManager   // it's a singleton
{
   vector<CGUIObject*> guiObjects;
   void drawObjects();
};

And the main.cpp:

CGame* g;

int main()
{
   g = new CGame();

   while(1)
   {
      CGUIManager::Instance().drawObjects();
   }

   return 0;
}

What would be the best approach to provide the screen size to each CGUIObject?

\$\endgroup\$
1
  • 3
    \$\begingroup\$ void draw(int screenWidth, int screenHeight). Keep it simple. \$\endgroup\$
    – ccxvii
    Nov 21 '12 at 15:14
2
\$\begingroup\$

There are a few decent options:

  1. As stated by ccxvii. Pass the width/height of the canvas to CGUIObject::draw();
  2. Pass your CGame object to the draw()
  3. Make CGame a singleton
  4. Redefine what CGame is and store graphics information in something called CGraphicsManager.

But yeah.. keep it simple for now, I'd go with #1 or #2.

\$\endgroup\$
1
\$\begingroup\$

I certainly advocate Fabien & ccxvii's advice to keep it simple and passing values to the draw() method is certainly a very logical approach for something small.

In the case of a larger more complex game, you usually have some windows system that helps in abstracting away the OS's windowing implementation. If some other system needs to know if the game window gets resized, it adds a listener that can be used to notify those interested when that happens.

struct IWindowListener {
  virtual void OnWindowResized(IWindow* window);
};

class WindowManager {
public:
  void AddListener(IWindow* window, IWindowListener* listener);
  void RemoveListener(IWindow* window, IWindowListener* listener);

  ListenerList& getListeners(IWindow* window);
};

class Window : public IWindow {
public:
  Window(WindowManager* owner) : mOwner(owner) { }
  void AddListener(IWindowListener* l) { mOwner->AddListener(this, l); }
  void RemoveListener(IWindowListener* l) { mOwner->RemoveListener(this, l); }

  // some method that fires when window gets resized by OS
  // This notifies all listeners who have interest.
  void WindowResizeFinished() {
    ListenerList& listeners = mOwner->getListeners(this);
    ListenerList::iterator start = listeners.begin();
    ListenerList::const_iterator end = listeners.end();
    for(; start != end; ++start)
      (*start)->OnWindowResized(this);
  }
};

class GUIManager : public IWindowListener {
public:
  void OnWindowResized(IWindow* window) {
    mWidth = window->GetWidth();
    mHeight = window->GetHeight();
  }
};

// Somewhere in your Game's initializing code
mWindowManager = new WindowManager();
mGUIManager = new GUIManager();

mGameWindow = mWindowManager->CreateWindow("My Game", 800, 600, WNDPOS_CENTERED);
mGameWindow->AddListener(mGUIManager);

This allows you to apply things like Separation of Concerns and Single Responsibility Principals to keep your code clean and separated into logical modules.

Again, keep it simple to start is important but realize there are some nice design patterns using the observer pattern shown above that can really make your code look elegant and clean and remain modular, extendable, and easy to maintain.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.