Patterns in games

After programming with an object oriented language for some time you start to see the same design structures appear. When you program a new application you naturally start using the same structure you have used successfully before. These common approaches to design are known as patterns.

You then start to think that there must be other common design solutions that you do not know about and would it not be great if you could have access to them? This is exactly what four programmers thought and so they created the now famous Design Patterns book (Design Patterns, see Resources). The gang of four (GOF), as they are known, described a number of patterns in their book. Others have since defined more patterns.

Patterns in games

Games programming is just a specialised type of software engineering that can benefit from the use of patterns. The distinct thing about games is the requirement for highly optimised code which can sometimes cause games programmers to avoid good software engineering practices. This, I think, is generally a false idea as there is no point having fast code that is hard to maintain or at the worst simply does not work! My advice would be to develop your game aiming to make it as robust as possible and then toward the end carry out optimisations for speed.

Some Common Patterns

The Singleton pattern is probably the best known pattern. The motivation for using this pattern is that sometimes we want to enforce the fact that there can be only one instance of a class. This often comes from the problem with dealing with global objects. One reason why globals are a problem is that there is no way of enforcing their creation and deletion. So one are of code may delete a global required by another. However global objects can be a good thing in C++ programming because you often have an interface to a game component that needs to be accessed from all over the game e.g. resource component, graphics component, world component, texture manager. These components should be designed so that one class provides all the interfaces to the component while the insides of the component are hidden. This is a good design idea but the problem is we only want one instance of our component and we want to be able to control it's creation and deletion.

The Singleton pattern can enforce these rules. The first time it is accessed it will be created and subsequent accesses will just return the one instance. This is achieved by having the class maintain its own instance pointer.

e.g.

class CSomeClass
{
    private:
          static CSomeClass *_instance;
    protected:
          CSomeClass(void);
    public:
          ~CSomeClass(void);
          static CSomeClass& GetInstance();
}

The _instance variable above is static so there can only ever be one of them. It is a pointer to an instance of the class.

The constructor is made protected so nobody can create an instance of this class without using the singleton interface.

The function GetInstance() is how the sole instance of this class can be accessed, this is normally defined in the source file e.g.

// Initialise singleton instance
CSomeClass *CSomeClass::_instance=NULL;

CSomeClass& CSomeClass::Instance()
{

  if (_instance==NULL)
  {
    _instance = new CSomeClass;
  }

  return *_instance;
}

This function will create the instance if it does not exist else it will return a reference to the instance.

So you can see that the Singleton pattern forces there to only ever be one instance of a specific class. It holds a pointer to that instance as a static variable and provides the GetInstance function to retrieve a reference to it. I normally simplify access by using a #define in the header e.g.

#define gSomeClass CSomeClass::GetInstance()

Then whenever I wish to use functions of the class I can do this:

gSomeClass.SomeFunction();

There are other ways of implementing this pattern, one in particular is pretty neat it declares the instance as static in the Instance function.

It is worth noting that not everyone approves of the Singleton due mainly to it being a 'glorified global'. My argument though is that if you take away the problems with using globals e.g. no control over deletion, creation, access etc. which a singleton does then it is OK.

The Abstract Factory pattern is another common pattern seen in games. Often you will find yourself needing to create instances of entities on request. e.g. world entities (bullets, soldiers, aliens...) , graphic entities (particles, billboards....). These are often child classes e.g. in the world the base class may be CWorldEntity and in the graphics component it may be CGfxEntity. So in our game we may wish to ask for a bullet instance to be created and stored under its base class pointer. The factory pattern handles the creation of entities based on the type required. One method that takes a parameter detailing which of the child classes to create is all that is needed.

A Regular Factory is like an abstract factory but does not deal with inheritance so it will simply have one method for the creation of each type of object.

The Facade pattern describes a class that provides a single unified interface to a set of interfaces in a subsystem. By defining this higher level interface it is easier to use the subsystem. We want to reduce dependencies in our code between subsystems to make them easier to maintain and alter. We can do this by sending all requests via a high level facade class. The facade knows which subsystem class to pass requests on to but each subsystem need have no knowledge of the facade.

The Composite pattern composes objects into tree like structures representing hierarchies. An example may be a game level where we have a number of different pieces e.g. sub levels, trees, enemies etc. and we want to gather them together in a collection.

Further Reading

A superb site that describes a number of patterns is data & object factory. Here patterns are broken down and code snippets shown.

The book Core Techniques and Algorithms has a good chapter on patterns in games and of course the original Patterns book is worth a look (for more details of both these see the Books page).



© 2004-2016 Keith Ditchburn