I'm feeling the need, to write blogs people won't read.
EDIT: Link to Part 2Over 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. :PSingleton 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();
}
#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();
}
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.
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 needI'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.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:
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.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.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).