2
\$\begingroup\$

I've spent a few months now working on a fairly simply 2D game engine with SDL and C++. I'm now trying to develop a simple but well-featured GUI suitable for most games.

Right now I'm really struggling on figuring out how I should handle communication between the GUI and the other parts of the game / engine that might want to use it.

For example, the "shop" game state may have a list of items that I want to display on a shop GUI, along with their prices and quantities, i.e "Wooden sword / 30GP / 5". Obviously I need to get this information to the GUI in order for it to be useful, along with a way of notifying the shop component which item has been clicked/given focus. Seeing as the internal representation of an object such as an "item" or an "inventory" can vary wildly, how do I get the data I want to/from the GUI in a way that doesn't require excessive coupling between the two components?

I'd really appreciate anyone's advice on how to approach this issue, and I fully appreciate that my understanding is flawed.

Finally, I'm set on developing it from the ground up as a learning exercise, so I'm not really interested in GUI libs for SDL (it seems none of them are updated for SDL2 anyway).

Thanks in advance

\$\endgroup\$
3
\$\begingroup\$

Basically, you need to know how GUI libraries work. In fact, you could even have a look on some of them to see how they get these things done (for example, you may have a look at GTK+ docs, or Qt docs to see the interface)

However, assuming that you're not building the whole GUI library, but rather some basic Window/Text/Image/TextLabel/Checkbox/RadioButton/Button library, I am going to share one possible approach how to do it.


Intro - rendering & data storage

Let's say you have a Window class. It already handles some basic functionality, like rendering and moving. The class also takes care of adding widgets. Widgets are Text or Image, for example.

class Window
{
    ...
    void render() const;    
    void move(const Vector & offset);
    void addWidget(const Widget newWidget); // Or you could use a reference, it depends on where do you want to store them/if you want to manipulate with them during their lifetime
    ...
}

Of course, you could be adding widgets to some grid cells, or you could give some offset relative to window on top of that.

Widget class could look like this:

class Widget
{
    ...
    virtual void render() const = 0;
    ...
}

I think it's clear for you now how you populate the window with the necessary information. Widget - derived classed will contain them. For example:

class Text: public Widget
{
    Text(const std::string);
    ~Text();

    void render() const
    ...    
}

// Somewhere else in your code
for (const int &obj : weapons)
    windowListingAllTheWeapons.addWidget(Text(obj.getName()));

The widgets will be displayed by calling their render() methods in the render() method of the window, which stores all the widgets (or references/pointers to them).

Handling events

Now all you have to do is to add some handleEvents() method to Window, which will call handleEvents() of its respective widgets. This may get complicated, but as long as you stay in one-layer-depth, it's easy-peasy.

handleEvents() will take care of catching events which occurred in the area of the widget and Widget will invoke onEvent() methods (for example onClick(), onHover(), onMouseRelease(), etc), which will be appropriately overrided in the derived classes.

Widget::handleEvents(Event & event) // I don't know exactly how SDL handles events. I assume here that all the mouse events caught in Window class get distributed based on their position
{
    // this is kind-of-a-pseudo-code. I don't know SDL
    if(event.type == Event::Type::MouseClick)
    {
        onMouseClick(Mouse::getPosition());
    }
    // Yeah, it's better to use switch for multiple options
}

Button::onMouseClick(const Vector & position)
{
    this.setClicked()
    this.invokeSomeOtherAction()
}

Disclaimer

This is not a tutorial on creating a GUI library. It's how I make GUI for small, not-GUI-heavy games. This is an overview of the process of creating quick'n'dirty GUI system. Anyone reading this, who is more interested in the topic should have a look at Observer pattern, Qt's Signal And Slot, MVC and should spend some time researching even more approaches on how to implement GUI.

\$\endgroup\$
  • \$\begingroup\$ Alright - this seems to be pretty foolish after reading it. Let me know if it's too stupid, so I can remove it :D \$\endgroup\$ – sjaustirni Apr 28 '15 at 19:11
  • 2
    \$\begingroup\$ Thanks for your response. This is actually exactly what I needed for my purposes. I was overthinking the design and not paying attention to the fundamentals. Thanks again! \$\endgroup\$ – Triforcer Apr 28 '15 at 20:00

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.