This is a topic I've been struggling with myself. We know that in object oriented programming, design patterns are tried and true solutions to problems we encounter. However, we usually don't employ design patterns to solve problems, we employ them usually without knowing it or because it seems like a good idea and we were taught to do it. This might be ok because it helps us avoid problems, but it simultaneously masks the problems we're (unknowingly) avoiding and makes it difficult to understand why the pattern exists, or why we would choose one pattern over another.
What a Design Pattern Is
Design patterns are generalized solutions to generalized problems that occur with some modicum of frequency when you're creating software using the object oriented programming paradigm.
Why Use Design Patterns
The most basic and condescending answer is: because these solutions have existed for a relatively long time and many experts have used them, they're likely better than any solution you could come up with on your own. And even if you did come up with a solution on your own, it's likely already a design pattern in some way. Knowledge of contextually pertinent design patterns helps you to make good architecture and design decisions.
Common Game Programming Patterns
- Singleton - You create objects that ensure that only a single instance of which can exist at a time. In my game Total Toads, this is the design pattern used because it was easiest to fit with cocos2d's design. For example, in cocos2d, there's a Singleton CCDirector, CCSpriteFrameCache, etc. It seems this is an often-used panacea in game programming. Though the general consensus seems to be that it isn't a panacea so much as it is a cancer because it actually masks poorly designed architecture. You should probably avoid using this design pattern if you can because there's likely a better way to design the architecture of your game. This can avoid the problem of having multiple instances of objects of which there should only be one, like a "Player" object in a single player game.
- Factory - You create an object whose purpose it is to create other objects. For example, you can have a factory class called "GameObjectFactory" with static (possibly parameterized) methods to create other game objects like a "Player", "Enemy", "Gun", or "Bullet". The latter classes might have complex constructions that make obtaining a instance of that specific class difficult. The factory can take care of the object's complex configuration (adding to an object pool, adding to physics engine, etc) and simply return a reference to the created object. This pattern helps you avoid the problem of complex object instantiation by keeping these complex configurations in a single place, rather than scattered around in your code.
- Observer - The object in question maintains a list of other objects that are interested in its state and notifies these listening objects of a change in its state. In Total Toads, we have 3 Frog objects and 3 FrogAnimation objects that can control the animation of the frogs based on their state. In this case, the FrogAnimation objects are observers of the Frog objects. Every time the state variable for a Frog changes, it notifies the associated FrogAnimation object to notice the new state and take an action if necessary (like animating the frog). This pattern helps you avoid the problem of event notification in your game. Since games are user-interaction driven, objects can change state at almost any time. When an object changes state oftentimes that object needs to be animated or have other objects change their state with respect to the new state.
- State - You have an abstract (empty implementation) class that has subclasses to define the current state. An example of this might be a first person shooter that has a "Player" class who has several possible states like "PlayerInCombat", "PlayerOutOfCombat", and "PlayerInMenu". When the state is changed, the player shall be represented as an instance of the appropriate state class. When the player starts to be shot at, the player object "switches" to an instance of the PlayerInCombat class to take advantage of that class's implementation of the mouse's left button click which makes the player able to shoot their gun. Similarly for the "PlayerOutOfCombat" and "PlayerInMenu" classes, where the mouse might allow usage of items or the clicking of menu options, respectively. This pattern helps you avoid monolithic methods that perform differently based on the object's state by having a bunch of switch or if/elses in your code. Instead, the object just changes and runs its appropriate code. This also simplifies your code and allows you to more easily find problems in your objects behavior since the state is right in the object's class name.
I don't pretend to be an expert game programmer...I'm nowhere even close to one, my first game hasn't even hit the market yet! However, this subject seems to not be extremely well represented or explained on the internet...and I would love an expert book on this specific subject. There's many more patterns than the ones I explained here, and you can find ok explanations in my below references. I'd appreciate it if some experts mentioned additional patterns that should be covered and why.
- David Kalina - lead programmer at TigerStyle
- Wikipedia links embedded in article