5
\$\begingroup\$

I'm currently working on a 2D game engine in XNA, and I am very interested in architecture, and how best to let my game objects communicate.

I know a lot of people use a Singleton design but I believe that this is more of a "counter-architecture" way of doing things, as every class will have access to the Singleton.

I was comtemplating using a Service-type architecture to allow for my Input, Sound, etc Manager classes to be available, but this is essentially the same problem as the Singleton as all the Classes are available to 'whoever' wants them.

I could of course pass references to the objects when they are needed, but this is bloated.

I wonder if making the 'Services' only allow certain objects to subscribe would be possible?

So is there a better way to make your classes available?

Or am I searching for an answer that doesn't have a question?

\$\endgroup\$
4
  • 3
    \$\begingroup\$ Take a look at gameprogrammingpatterns.com. Programming patterns are explained from a game programming perspective. \$\endgroup\$
    – smack0007
    Commented May 27, 2011 at 11:04
  • \$\begingroup\$ 3nixios: I added an answer to answer the question you asked in someone's answer's comments. \$\endgroup\$
    – Olhovsky
    Commented May 27, 2011 at 12:30
  • \$\begingroup\$ The term you are looking for for singletons and the like is anti-pattern :) \$\endgroup\$ Commented May 27, 2011 at 18:19
  • \$\begingroup\$ Have a look at the component-based architecture, gamedev.stackexchange.com/search?q=%5BC%23%5D+component \$\endgroup\$ Commented Jan 27, 2012 at 5:10

6 Answers 6

8
\$\begingroup\$

When you're writing a game, you're better off writing a game than worrying too much about having the perfect architecture. There's nothing really wrong with having singletons and global variables in a game. Far better to have less and more flexible code than for it to be perfect.

I personally find that Singleton is a pattern to be avoided. Most of the time you should be using a static class or member instead of a singleton. See, for example, the Mouse and Keyboard and MediaPlayer classes in XNA. These are all simply static classes which are globally accessible.

I would query your need for a "sound manager", seeing as SoundEffects are stand-alone. And ContentManager is already the only thing you need to "manage" them.

You don't really need to write a services architecture, because XNA already provides one (see Game.Services).

If it seems like it would help, there's no reason why you can't just add a public static MyGame theGame member to your Game class and effectively turn it into a singleton. For the simple reason that there is never reasonably going to be more than one instance of your game class. Then you can make its members public (Content and Services already are) and access them globally, if it makes sense. This is simple. You can always change it to something more complicated later!

Making only your Game class a globally accessible also keeps the global access point localised to one place in the code, making it easier to locate when you want to "un-globalify" something later.

What I would very much avoid is making true Singleton classes that can only be instanced once. For example: don't make a map class that you can only create one instance of: what if you want to add background loading of the next map later? (Or the player class - for multiplayer, and so on).

The best example of this "global but not singleton" in XNA is ContentManager. You've got Game.Content which is effectively global. But you can also create more instances of ContentManager, which can be owned by whatever you like (levels, screens, whatever) and will operate independently.

\$\endgroup\$
4
  • \$\begingroup\$ Russel: I do believe sir that I like your view on things. I would agree in general but the idea is to make an architecture for rapid gameplay prototyping, it is therefore much easier for me to have Managers that are accessible via Properties for example. So I guess this is answered. I have now reached a sense of tranquility. \$\endgroup\$ Commented May 27, 2011 at 12:43
  • \$\begingroup\$ Andrew Russell: Since you asked about the need for a sound manager... My sound manager manages sound resources (with an object pool) and automatically chooses appropriate sound fading between players in splitscreen. The sound manager also allows you to "fire-and-forget" sounds, for sounds that are short, so there is no need to get a new sound instance from the object pool and release it when it's done playing. You can simply do SoundManager.Play(Sounds.Beep2); If you don't put this type of functionality in a "SoundManager", then where do you put it? \$\endgroup\$
    – Olhovsky
    Commented May 27, 2011 at 12:51
  • \$\begingroup\$ @Olhovsky: It sounds like your use of a sound manager is appropriate, if XNA's built-in fire-and-forget functionality does not meet your needs. Whether you make this a simple static class with a static pool, or you make it instanceable (and then what "owns" it), will depend on your game. \$\endgroup\$ Commented May 27, 2011 at 13:00
  • \$\begingroup\$ Static classes in languages where they can hold state, i.e. have private static fields, are singletons. The problem is that some people are too inexperienced and believe that the pattern as implemented in other languages is some kind of golden rule, which it is not. If you program pattern oriented you are just over-engineering, not actually solving the problem at hand which in most cases is very specific. Patterns serve solving a common problem not the other way around. Need some data that has to be accessed globally? You'll either endup passing it as argument everywhere, or make a singleton. \$\endgroup\$
    – Trinidad
    Commented Jun 16, 2011 at 20:41
10
\$\begingroup\$
I could of course pass references to the objects when they are needed, but this is bloated.

No, that's completely how it should be done. If you find doing this untenable, then your design is broken.

Passing references makes for the easiest, most obvious control and encapsulation. Global data is bad, whether you want to call it a "Singleton" or a static Manager. You shouldn't even need an InputManager or a SoundManager.

\$\endgroup\$
17
  • 1
    \$\begingroup\$ Why shouldn't I need an InputManager or SoundManager? I don't want all Input & Sound code directly in place whenever I need to check someting... Of course encapsulation would be easy if we only have a few classes... \$\endgroup\$ Commented May 27, 2011 at 11:56
  • \$\begingroup\$ @3nixios: If you make a Sound object, then it is your responsibility to keep it around as long as you still need it. Sound-related code goes in the Sound class. What exact function are you hoping for your Manager to achieve? The same is true of Input. \$\endgroup\$
    – DeadMG
    Commented May 27, 2011 at 12:08
  • 1
    \$\begingroup\$ @3nixios: So make a SoundBank class that holds a SoundBank, and have it create Sound objects from cues within that bank. There's still no need for global data- if you can't conceive of a manager-less design, then pass the managers as references. \$\endgroup\$
    – DeadMG
    Commented May 27, 2011 at 12:23
  • 2
    \$\begingroup\$ @Gajet: Your comment. Global accessibility and single-instance objects are really two separate issues. Global accessibility is fine. Single-instance is a very bad idea. Strictly speaking, a class that is "Singleton" is not necessarily globally accessible. (This is the basic thrust of my answer.) \$\endgroup\$ Commented May 27, 2011 at 14:38
  • 4
    \$\begingroup\$ Gajet: Actually you usually want more than one object pool (I have dozens typically), and having a singleton isn't really necessary for ensuring that you only have one graphical API. In fact, why do you need to ensure that at all? \$\endgroup\$
    – Olhovsky
    Commented May 27, 2011 at 17:40
1
\$\begingroup\$

The major difference between the singleton approach and the service locator approach is that the components are more loosely coupled. If Foo accesses Bar as a singleton, any changes to Bar affect Foo indirectly.

With a service locator you can communicate through an interface though, IBar say. You can change Bar all you want as long as it fulfills the IBar contract. If you decide that the class Baz should now fulfill the IBar contract, you can just swap it out. With the singleton, you can't do that so easily.

\$\endgroup\$
2
  • \$\begingroup\$ Good point ^^. I do much prefer the Service Locator, only I can't help but think to myself that it's kindof like making your services globals or using Properties to access them, which is horrible :). \$\endgroup\$ Commented May 27, 2011 at 11:18
  • \$\begingroup\$ I honestly prefer constructor injection. It makes it clear what dependencies a given object has. With a service locator, it can be hard to know which components depend on which other components. \$\endgroup\$
    – smack0007
    Commented May 27, 2011 at 13:54
1
\$\begingroup\$

My advice is that a good programmer isn't dogmatic. Passing things by reference is good, singletons are also good. A good programmer uses every weapon in his arsenal, they don't rely on using a single tool, a hammer can't solve every problem.

For instance I would say it is a bad design to be passing around the same reference to a single object everywhere.

Singletons aren't counter-architecture, they're part of the GOF patterns and it is an extremely useful pattern. As all architecture, they have a proper time and place, architecture for its own sake is a common mistake. A singleton is appropriate when there should only ever be one instance of that class in your application and that instance is referenced everywhere.

You want to restrict access to singletons? A good design is not just about classes, its also about appropriate packaging. By using the internal C# access modifier you can limit use of a singleton to within a particular package/assembly.

\$\endgroup\$
0
\$\begingroup\$

This is a problem throughout all of software development, and there are several common solutions.

Fortunately, you don't really need to pick one - XNA already has a built-in service locator!

\$\endgroup\$
-6
\$\begingroup\$

I think you can use mutiple inhertence for your need and have some game object like these :

class KeyboardReader
{
    protected :
    static KeyBoard* keyboard;
};

class MouseReader
{
    protected:
    static Mouse* mouse;
}

class gamecontroller:public KeyboardReader, public MouseReader
{

}
\$\endgroup\$
10
  • \$\begingroup\$ Thanks but my question is more about global architecture, not inheritence. \$\endgroup\$ Commented May 27, 2011 at 11:25
  • \$\begingroup\$ and that's what my answer is all about, for all your resources you have a base class that can use that, and every class that need to use resources, should inherit from classes that provide them, in these architecture there is no need for singleton but you still have some static variables in your code. in this approch the keyboard value in KeyboardReader is once initialized by some class, (for example main function) and after that it's that value is shared with all the classes that inherit KeyboardReader. without passing keyboard to them or defineing Keyboard as a singleton. \$\endgroup\$
    – Ali1S232
    Commented May 27, 2011 at 12:41
  • 1
    \$\begingroup\$ -1 because c# doesn't support multiple inheritance \$\endgroup\$
    – Tetrad
    Commented May 27, 2011 at 17:01
  • 2
    \$\begingroup\$ Also this is exactly the kind of overuse of inheritance that people have been shying away from. A game controller should not have a "is a" relationship with an input manager. At the very least you should make the inheritance private. But a less messy solution (for example, to avoid multiple inheritance name collision) would be to use composition, but since in this case you're using static instances you'd have to make them public anyway, the composition members wouldn't actually do anything, so you might as well make them globals. \$\endgroup\$
    – Tetrad
    Commented May 27, 2011 at 17:16
  • \$\begingroup\$ -1 What will you do with a Trackball, Multitouch Screen, Gamepad? Inherit from them too? What about a second Game-Pad? Really terrible design! \$\endgroup\$ Commented May 27, 2011 at 17:54

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .