Wednesday, December 11

Design Patterns

In this blog I will go over several of the most prominent design patterns used in game engine programming.  I will not cover why they are considered good or bad; just their functionality.  Design patterns are common code structures that can help streamline engine code and make it easier to use, not to mention more efficient.  I will be going over the most important: singleton, factory, facade, and finite state machine.

A singleton is a very simple design pattern but it can be very beneficial to ensure to help manage how you use global variables.  A singleton object may only have one instance of it at a time, ever. It has a single static member which can be of whatever type you specify.  The only function it contains is a Get() function, to retrieve the data.  Singletons are useful anywhere you only need a single object of any type, such as a renderer, mouse input, etc.

class Singleton
{
   public:
      static Singleton* getInstance();
      Singleton();

   private:
      static Singleton* s_instance;
{

This simple class declaration shows the getInstance(); function which would retrieve the s_instance; provided that you have initialized it.

Singleton* Singleton::getInstance();
{
    if(!s_instance)
        s_instance = new Singleton();

    return s_instance;
}

This is the getInstance(); function that will retrieve the member.


A factory relies on polymorphism to enable its functionality to accommodate as many objects types as you need.  It essentially functions as its name implies; a factory can create multiple objects of various types based on the parameters you give it. Through polymorphism it is able to create different object types which inherit certain common attributes.  Factories are great because you can easily add new types of objects for it to make, and just have them inherit most of the values, then include their specific ones.


Entity *entityFactory::createObject(int type)
{
    Entity *object = null;
    switch(type)
    {
       case cube:
          object = new cube();
          break;


       case sphere:
           object= new sphere();
           break;
    }
    return object;
}


This code will create a new empty object, then assign it to whichever type of object you specify.  It then gets returned as a cube/sphere etc.  This can be done as many times as needed for any types of objects that need to be created (world objects, npc's, items, etc).


A finite state machine is often used for AI but can be applied to many different areas of a game engine.  It basically keeps track of N number of states that can be changed/turned off and on.  For example you could use it to manage which types of enemies are spawning in a particular level (each type of enemy would have on/off for spawning).  It is not just limited to objects, but any number of types that you can represent with an object.  There can be more than two states for any variable.  FSM's are useful because each state for a switch can inherit the necessary functionality and data, making FSM's easy to extend and modify.

StateManager *newSwitch::createSwitch()
{
   StateManger *enemyType = new state();
   switch(enemy)
   {
   case normal:
      enemyType = "normal";
      break;

   case strong:
      enemyType = "strong";
      break;

   case boss:
     enemyType = "boss";
      break;
   }
    return enemyType;


The above code is a simple three-way state which determines which enemy type the current enemy will be.  Through polymorphism, this code could be used to set the type of any class of enemy in the game.  For example you could set a soldier to normal type and set an assassin to boss type.


A facade is similar to a factory but it does not actually create new objects; it manages them instead.  It works like a manager at a company: overseeing and organizing all the 'workers' or classes underneath it.  These can be singletons such as various subsystems in the engine (audio, input etc).  The facade pattern is used to allow each of these components to communicate with each other more easily.  Doing so allows the structure of the engine to become more modular and it becomes much easier to add/remove/modify specific components of it.

class ClassManager
{
    public:
      ClassManager *getClass();

   protected:
      ClassManager();
      ClassManager *getClassType();
      ClassManager (const &ClassManager();

   private:
      static Class*  audioClass;
      static Class* inputClass;
      static Class* managerClass;


This is simple setup code for a facade-type manager class.  It can get the name or type of a class and contains the set of singleton classes that it will be managing.


There are many other design patterns that I didn't cover such as iterators and observers, but they are also fairly simple and should definitely be used in your game engine if it will help the efficiency and ease-of-use for it.  Design patterns are patterns because they are easily repeatable and can greatly enhance the modularity of your engine.