2

I am working on developing a game engine using DirectX 11 and C++ (using the default Visual Studio template) and I have some questions that I cannot find answers to online.

So there are three main components for the game, the actual game class, a renderer and a logic class. The game class would look like this

class Game {
    Game();
    ~Game();

    Logic* m_Logic;
    Renderer* m_Renderer
}

(If you are curious, I am doing this for two reasons, 1. to play around with classes, I've done it the conventional way before so I want to try something else and see if it has any real benifits. 2. so that the code for both are completely abstracted from eachother)

My question here is if it is a bad idea to make the two subclasses into singletons (given the game class is). I understand when and why one might use them, but considering that there will only ever be a single instance within the game class, would this work fine? What if the game class wasn't a singleton, and could instead run multiple copies at the same time (thus allowing for running multiple games at the same time, once again out of curiosities sake)

NOTE: Since everyone keeps pointing this out. I know they aren't a good idea. This is a test/experiment. I am having my fun programming. Let me have my fun :P

EXAMPLE: An example of why I might want a renderer to be a singleton when the game class can have multiple instances. Since the renderer will be identical between different instances of the game, there is no need for there to be multiple instances of it. Think of it as a container of all the functions that just takes the various variables stored in the game class and does the things to it to output to screen. Same goes for the logic class.

Maxim Srour
  • 157
  • 1
  • 17
  • 1
    Singletons are never a good idea. – user253751 Jun 19 '18 at 04:33
  • In the case of the game class, since I will (usually) only ever want one running at a time, it makes sense to run it as a singleton. Either way, like I explained, this is all an experiment. I would much rather just use Unreal or Unity if I wanted to make a game, I enjoyed making an engine years ago and would like to do it again, but better/different – Maxim Srour Jun 19 '18 at 04:39
  • Why are you using pointers ? – Sid S Jun 19 '18 at 04:46
  • 3
    I repeat, singletons are never a good idea. Singletons are just disguised global variables that you use to kid yourself into thinking you're not using global variables. As for *why* they're a bad idea, global variables are the reason Minecraft couldn't have the Nether on servers until Beta 1.6. Everywhere was using `MinecraftServer.get().theWorld` and had to be updated to work properly with multiple worlds. – user253751 Jun 19 '18 at 04:58
  • And I'll repeat myself too. I am experimenting and playing around with everything. I don't care if it's 'a bad idea', I want to try it out and see what happens and then learn from it. And it's quite easy to avoid the kind of issue outlined if you understand the scope and work to it. I know a game will only ever have a single renderer so I only need one, and one alone. @Sid S because I don't want the entire class in the stack, I'd much rather the game class point to the actual class (giving itself as a reference). Just how I learned things – Maxim Srour Jun 19 '18 at 05:11
  • I really don't think you are reading my comments (or post, for that matter) properly. _I intend to screw around with this code and to try something different, I want to use singletons and I want to make it work. I don't care if it is 'bad design', I learn from my mistakes, that's why I have a job in software development unlike many of my peers who only focus on doing it 'the right way'_ – Maxim Srour Jun 19 '18 at 05:59
  • I also do hope you understand that this is completely irrelevant to the topic at hand – Maxim Srour Jun 19 '18 at 06:02

1 Answers1

2

Some would say that "Singletons are never a good idea", but this statement is not held by engineers behind many popular game engines to this day. I will advise you to minimize their use everywhere possible, but there will be situations that they are well-suited for. In fact, "Game Engine Architecture" written by Jason Gregory over at Naughty Dog has a whole section on their uses. I will give an example that I kind of regard as a hybrid approach.

If you read through the code base of Unreal Engine (or at least use the engine), you will find something along the lines of:

extern class UEngine * GEngine

UEngine is actually the base class of all Engine implementations (and there are multiple as there is a need for different variants). During startup, the launcher determines which variant it needs to load and then proceeds to construct a single instance that the entire system will then use. This is similar to your approach, but rather than making multiple Singletons, you can have a global reference to your Game object that gets set once during initialization:

extern std::unique_ptr<Game> game; // Global game reference in some .h file

(in .cpp)
std::unique_ptr<Game> game;
int main(int numArgs, char ** args) {
    game = std::make_unique<Game>( ... ); // Initialize game exactly once!!
    ...
}

This approach allows you to do some interesting things, especially if you make Game an interface like the engineers behind Unreal Engine decided to do and then have multiple implementations depending on the need behind it.

Should each object that Game maintains be a Singleton? I would not think so as it actually limits what you can do later. Game needs to at least support the following:

  • Creation, start up and shut down of things like Logic and Renderer, in the correct order (it owns all of these objects it creates, so all code that interfaces with Game inevitably interacts with them!)
  • Ability to retrieve references to things like Logic and Renderer, or whenever possible keep them hidden but provide a limited interface to gain access to their functionality
  • Since Game is now your only/one of your only global variables, it becomes the gateway into your engine environment and thus you can do a lot of stuff to encapsulate the components that it maintains rather than making many singleton objects

I consider this a better approach than making all of your core classes singletons.

Stephano
  • 356
  • 1
  • 5
  • Thank you for your answer. The code you provided is what I would normally use to create the game class, but it got me thinking, why not with some of the other core elements that the game maintains. Since only one needs to exist, it wouldn't necessarily be detrimental. Though that does beg the question, how would it react if I then created multiple instances of the game class (with singleton elements)? Obviously this is just a bad idea, but I enjoy screwing with code and seeing what I can do with it – Maxim Srour Jun 19 '18 at 05:21
  • Yeah, something you can do to mitigate that is to make your Game's constructors private and have it list a single friend class (maybe "GameLauncher" or whatever). GameLauncher would be responsible for creating the one and only instance of Game, and no other piece of code could do it. Plus, if you make every core class a Singleton, no one really owns them, not even Game. Making it clear who is responsible for initializing/shutting them down is then harder to define and enforce. – Stephano Jun 19 '18 at 05:25
  • That makes sense. I did something similar with my last game engine. In the case you outlined, I would have those core classes created externally and just fed into the constructor, eg `logic = new Logic(); renderer = new Renderer(), game = new Game(logic, renderer)`, and then later have those be cleaned out by the same game launcher. These are just ideas I have, no clue how bad (if at all) this is. I know one parallel to the Unreal engine, which is the Input controller. Only one exists, and is just fed into each class as required. – Maxim Srour Jun 19 '18 at 05:33
  • For another take on the singleton, read up on [the Scott Meyers singleton](https://stackoverflow.com/a/1008289/4581301) – user4581301 Jun 19 '18 at 05:56
  • I was actually reading that not long ago, which is what prompted me to ask this question. Very good read, has a lot of valuable information – Maxim Srour Jun 19 '18 at 06:00
  • There must be some detail missing, because it isn't clear from what you posted why you need a singleton at all, as opposed to, say, a single instance that you pass around. – juanchopanza Jun 19 '18 at 06:15
  • "Because I want to" is the only answer I can give you. I could easily do it without a singleton and just pass a reference as you stated, but what's the fun in that? I am not going to be making any games in this engine, and I definitely won't be shipping this off to anyone else, this is purely an educational journey for myself – Maxim Srour Jun 19 '18 at 06:26