Engineering Logs - Singletons

Posted by Astryl on Jan. 12, 2015, 1:40 p.m.

I'm feeling the need, to write blogs people won't read.

EDIT: Link to Part 2

Over the last year or two, I've been spending a lot of my time working on my ideas as quietly as possible. I have a 'major' game I'm slowly piecing together, bit by little bit.

One of the things that always slows me down is the engine I use for my games. I'm always torn between using an engine like GM, or creating my own.

I always want to create my own for the added benefit of being able to implement things that are unwieldy in GM, or even in Unity.

But as I've been noticing over the course of the last few competitions, I've always started out in C++ and ended up using GM (Or Unity in the case of Project Phoenix).

My work flow tends to involve drawing some initial artwork, and beginning work on the framework I'll be using. What usually happens not long after drawing the artwork is that I start to get anxious with regards to testing mechanical concepts, and seeing my animations in-context.

So I invariably end up just choosing the GM route for a quick game; at least with my competition entries.

In this case, especially with my long-term project (Called Fallen Keep), I've been sticking with C++ for the long haul.

My main reason for this is that it's far easier to express certain pieces of game logic in C++ than it is to fudge it out in GML.

Anyway, I've been working on the latest iteration of "my engine" for quite a long time now. About 18 months ago was when I started working on this game, and the new framework with it.

The engine that powers Exile was my original choice, but I realized shortly that the engine was very much locked in to creating 3D games; 2D games were too unwieldy. Much of the code was modified to fit into what I needed for the game.

If you ever want to see mangled code, give a programmer with nothing better to do a month and a simple 2D game engine, then tell him to make a Hexen clone.

Fallen Keep is 2D, and relies on the Core OpenGL profile for various effects. Exile primarily used Fixed Function OpenGL, and later mixed GL3.2+ features to add the lighting model I used for Abyss.

As a result, the render code is pretty much screwy. Rewriting in this case was the sane choice.

Anyway, enough rambling. I've learned a lot over the past year with regards to quickly implementing a game engine from scratch. A lot of experimentation has gone into this, and I decided to start writing a few pieces on some of the patterns and ideas I've been using for it.

Take everything with a pinch of salt. No doubt some of you will have an alternative, or 'better', way of doing things; that's fine. Discuss it, I'm always interested. :P

Singleton Pattern

This is a mildly polarizing design pattern; some people swear that you should use the things "wherever possible", whereas others insist they be treated as something akin to goto.

My opinion is that they fit the bill perfectly for their intended purpose: To provide the programmer an instance of a class, and only ever that one instance of that class.

Originally, I used to create purely static classes for things like this. The AssetManager class from Exile is an example.

There are downsides along with advantages to static classes, but in the end it boils down to aesthetic for me. I hate using the :: accessor outside of the only context I believe it fits: Namespaces.

Anyway, on to the actual definition of a Singleton.

The Singleton Pattern is a specific manner of coding a class in such a way that you can only ever instantiate a single instance of that class at any given time.

This might sound stupid to some, and in many cases it is. You wouldn't make, say, a GameEntity class a Singleton.

But for some things it provides an elegant solution to the problem of access.

A lot of 'tutorials' I've seen on GameDev and other sites that involve creating game engines tend to either make liberal use of global variables, or pass certain objects as parameters.

Something like this:

// Using some basic SFML code.
#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
#include <SFML/System.hpp>

void update(const sf::RenderWindow& window);
void draw(const sf::RenderWindow& window);

int main(int argc, char** argv) {
    sf::RenderWindow *renderWindow = new sf::RenderWindow(sf::VideoMode(640,480));

    sf::Event event;
    while(renderWindow->isOpen()) {
        while(renderWindow->pollEvent(event)) {
            if(event.type == sf::Event::Closed) { renderWindow->close(); }
        }

        update(*window);
        draw(*window);
    }
}

void update(const sf::RenderWindow& window) {
    // Do stuff, update view, etc
}

void draw(const sf::RenderWindow& window) {
    window.clear();
    // Render game objects
    window.display();
}

This is a 'flat' example, just here to show the concept I'm talking about. I've seen quite a few "C++" engines that depend heavily on coupling like this (The function definition requires another object to exist, instead of being able to exist on its own).

Decoupling is fairly important to building stable programs, in any given situation.

Some classes and functions are designed to work with each other, but in some cases you're passing references out like candy. Break or change the thing being passed, and you start getting potential cascades of breakages.

The point with the renderWindow variable above is that it's something that will need to be accessed by a large number of classes.

If I was using SFML's built in draw functions, every Drawable object would need a reference to the render window.

And things will get messy very quickly this way.

Static classes alleviate the problem somewhat, but in my opinion are somewhat messy to handle.

So I'll skip those and dive right into the same program segment above, reworked to use a Singleton class.

#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
#include <SFML/System.hpp>

#define INSTANCE(singleton) singleton::getInstance() 

class GSWindow { 
    public:
        static GSWindow& getInstance() {
            static GSWindow window;
            return window;
        }

        sf::RenderWindow& getRenderWindow() { return *this->renderWindow; }
    private:
        GSWindow(){
            this->renderWindow = new sf::RenderWindow(640,480);
        }

        ~GSWindow() {
            delete renderWindow;
        }

        sf::RenderWindow* renderWindow;
};

void update();
void draw();

int main(int argc, char** argv) {
    sf::Event event;
    while(INSTANCE(GSWindow).getRenderWindow().isOpen()) {
        while(INSTANCE(GSWindow).getRenderWindow().pollEvent(event) {
            // ...   
        }    

        update();
        draw();
    }
}

void update() {
    
}

void draw() { 
    INSTANCE(GSWindow).getRenderWindow().clear();
    INSTANCE(GSWindow).getRenderWindow().display();
}

Longer winded, perhaps, but neater… at least to my eye. :P

And yes, I'm using simple Macro expansion. I could also just call GSWindow::getInstance(), but I prefer the INSTANCE macro to be 'first'; makes it easy to read that I'm using one of the Singleton classes.

The 'creation' of a singleton can be automated somewhat with templates, but I prefer to hand craft them to a degree.

A way of creating something like "INSTANCE()" without using the pre-processor is to create a static method that operates on anything of the Singleton 'type', but I consider it too much work and extra processing to be bothered for the scarce few Singletons I use.

Anyway, back to the subject at hand.

This setup allows for a few things. First of all, clarity. Reading this code in my engine I see immediately that I am using one of the few Singletons I have.

Secondly, I can access everything with a guarantee that everything is initialized and ready to be used.

Thirdly, and class method or function can access and use the instance of GSWindow as long as it 'sees' the class declaration (Normally I'd split that GSWindow class into separate .h .cpp files).

So, a few notes. I only have three major Singletons in my engine, each of which are natural fits for the pattern.

These three Singleton classes are :

GSWindow - Wraps the sf::RenderWindow and associated window functions.

GSVFS - Virtual File System for game resources.

GSTasker - Task management system

The "GS" prefix stands for "Game" and "Singleton".

I had a GSInput class for a while, but decided that it was a poor idea if I ever felt like implementing multi-source input (for local multiplayer), or for input streaming (for demo playback, AI control, or even network play).

A little quirk you'll notice if you stare at the code hard enough is the way I implement getInstance(). I'm specifically taking advantage of the static keywork, initializing an instance of the class (Possibly on the Stack, depending on compiler and what the optimizer feels like doing, so don't get too carefree with them).

When the program ends, this instance falls out of scope and will automatically delete itself. Nifty, as it allows you to 'black box' the details of creating the instance.

Anyway, that's enough rambling for now. Next time I'll write about my VFS system, why I'm using it instead of my old AssetManager system, and maybe some other stuff.

Feel free to argue inefficiencies below; don't get too hard-assed about doing things 'right' though - there isn't any such thing as far as I care. If it allows me to make games, it's right for me.

Comments

Alert Games 9 years, 4 months ago

I use this in my APIs for database access, as well as in my clients for the API that handles the connection and communication between the client and the APIs themselves. However, since you could technically create more instances with different connections, they're not really 'singletons' but they almost might as well be since you would want to only use one instances of the classes.

s 9 years, 4 months ago

Being able to open multiple windows is useful long term, GLFW had to make that hard transition

Besides that, no point having an instance at all if a bunch of static functions & a few privately shared variables are all you need

Astryl 9 years, 4 months ago

I've only ever seen roguelikes bother to use multiple windows, in terms of games. And it tends to feel like a kludge. Games will, in most cases, only require one render target; any UI work is then done using that render target.

The only case I personally have for wanting more than one 'window' is for any editor tools I create. But in that case, I have a separate framework that uses wxWidgets specifically for working on my tools.

Static functions have their use, specifically when you need to create once-off utility functions that don't have any place in a class.

However, once you start creating functions that need to work together, allowing them to be accessed via an instance provides an immediately available context to work with that you know will work, without having to pass data around.

In my engine, GSWindow handles more than just the pointer to an sf::RenderWindow, it also loads its own configuration, handles window-related hotkeys (Switching to fullscreen, enabling/disabling VSync) and is also responsible for managing a GL context. Most of this is done through Component style classes; that would be a clusterfuck if I was managing this directly.

If I was just making a single game, I'd probably just use the most direct method possible, that being static classes/functions and a global static class for game state.

But what I'm doing here is creating a relatively flexible engine for future reuse, without locking it in to one specific type of game.

Nopykon 9 years, 4 months ago

I use them in Java, because of how Java is. Otherwise, almost never. If I need just-in-time initialization for a singleton object, I use this:

float*getSphereMesh(){
   static float vertices[1000];  
   Do dirty stuff to verts...  
   return vertices;
}

Less code, works in C, and since I am a lazy and alone forever programmer it doesn't bother me, doesn't confuse me, that is isn't tidied up in a class.

Good luck with your main project!

Astryl 9 years, 4 months ago

That works nicely for data like that, I've often done it too for in-place initialization.

Of course, I'm not just working with data; I'm working with methods too, thus the choice to use Singleton classes.

I've written up a piece on the VFS I'm using for my engine; will post it a bit later.

You guys had better get to writing blogs if you don't want the feed to become full of dry technical blogs.

Alert Games 9 years, 4 months ago

I think singleton's are the way to go because technically you could create more than one instance, it just wouldn't make sense really. But it also gives the opportunity to have parameters for the singleton for testing.

Also, yes.

Jani_Nykanen 9 years, 4 months ago

I have never used singletons in my projects, I have always used namespaces for main functions and variables, which is not the best method for obvious reasons since I cannot use the application variables (window pointer etc.) in any other C++ file (without references, of course).