Object Oriented Design Patters
The time has come, I need to do
another blog for my game engines course and I am not sure on a topic to talk
about. For inspiration I opened up my game’s code and started to step back and
look at it. While looking through my game code I relied that my game is made up
of a bunch of different design patters. So this is my topic for this blog. It is
time to get started.
Singleton Design Pattern
A singleton design pattern restricts
the object to only have one instance. If there was singleton class called
Singleton, then there can only be one instance of this object at any given
time. You can think of a singleton similarly to a static variable. Just like a
static variable there is only ever one instance of that object at a time. This
is done by creating a class and making the constructor private. When the
constructor is private you
can make sure that the user can’t
call it multiple times.
ExampleClass *example = new
ExampleClass();
Instead of creating a normal object
like the example above we can use a function to get an instance of the object.
An example singleton class is demonstrated below.
Singleton::getInstance(); // with the
example below can also be called by SINGLETON_CORE
1: // .h file----------------------------------------------------
2: // this macro can be used outside of the class to call on the instance
3: #define SINGLETON_CORE Singleton::getInstance();
4: class Singleton; // class prototype deceleration
5: typedef Singleton* (*FuncPtr) (void);
6: class Singleton{
7: public:
8: ~Singleton(); // default constructor
9: // the first time this is called it will also call createInstance to create the
10: // initial object and from then on it will call getInstance to return the instance pointer
11: static FuncPtr getInstance; // function to get the instance of the object
12: private:
13: Singleton();
14: static Singleton* createInstance(void);
15: static Singleton* instance; // static Object
16: };
17: // .cpp file--------------------------------------------------
18: // this makes sure that if the first time it is called that the instance is made
19: // if not then it will go ahead and create the instance and then return it
20: FuncPtr Singleton::getInstance = createInstance;
21: Singleton* Singleton::instance; // defining the static instance
22: Singleton::Singleton(){}
23: Singleton;:~Singleton(){}
24: Singleton* Singleton::createInstance(void){
25: if(instance == NULL){ // checking to see if there is no instance if there is not then make one
26: instance = new Singleton();
27: getInstance = Instance;
28: }
29: return m_instance;
30: }
31: Singleton* Singleton::Instance(void){
32: return m_instance;
33: }
Singletons are great for objects
that you only want one of. A great example of this is any sort of system manager.
In my game we have an input manager that handles all of the inputs. You do not
want multiple managers to control the input so we used the singleton design
pattern. There are many other design patters that act like singletons as you
only need one object of that type. The disadvantage of this pattern is that you
cannot create multiple instances, but that is the entire point of the pattern.
There can be problems with singletons and multiple threaded applications. If
you are to have two threads use the create instance function at the same time
they will both check and only one will get the instance. If you want a video
that explains singleton design patterns well then check out this link.
State Design Pattern
The state design pattern is an
object oriented behavior based design pattern. It is also referred to
the Objects for state pattern. This design pattern focuses on a base state
class and then all other possible state that can happen inheriting from it. In
a game context you can use the state design pattern for AI and the manager that
will go along with it. AI can be broken down into a list of different behaviors
that have been designed by the game designer. You can have a base class called behavior
and all other behaviors will inherit from this base class. Behaviors such as
seek, flee, and arrive can be behaviors that inherit from the base behavior class.
In the AI manager you can decide what behavior to do at any point in time. To change
what behavior you are currently running you just have to change the current behavior
state to the correct one. An example of this would be as followed.
1: class BehaviorState{
2: public:
3: virtual void doSomething();
4: virtual void ~BehaviorState();
5: };
6: class SeekBehavState public BehaviorState{
7: void doSomething(std::cout << "seeking" << std::endl);
8: // within this state you can change to other states
9: };
10: class FleeBehavState public BehaviorState{
11: void doSomething(std::cout << "fleeing" << std::endl);
12: // within this state you can change to other states
13: };
14: class AriveBehavState public BehaviorState{
15: void doSomething(std::cout << "arriving" << std::endl);
16: // within this state you can change to other states
17: };
18: // this class can be a singleton that handles all the AI or it can
19: // handle only one object it is up to your design
20: class Manager{
21: Manager();
22: // all of the different states
23: BehaviorState seekBehavior;
24: BehaviorState fleeBehavior;
25: BehaviorState ariveBehavior;
26: BehaviorState state;
27: void doSomething(){state.doStomething();}
28: BehaviorState getState(){return state;}
29: void setState(BehaviorState pstate){state = pstate;}
30: BehaviorState getSeekState(){return seekBehavior;}
31: BehaviorState getFleeState(){return fleeBehavior;}
32: BehaviorState getAriveState(){return ariveBehavior;}
33: };
34: int main(){
35: Manager m;
36: m.setState(getSeekState());
37: m.doSomething();
38: m.setState(getFleeState());
39: m.doSomething();
40: m.setState(getAriveState());
41: }
If you would like more information about the state design pattern with a great example implementation, check out this link.
Façade Design Pattern
If you would like more information
on the façade pattern along with example implementation, check out this link.
Factory Design Pattern
The Factory design pattern is used
when you want a function to return one of several classes which all have one
base/super class. An example where this would come in handy would be for
spawning entities in your game. You have a base class called GameObject which
all other game objects will inherit from. All of your enemy classes will inherit
from the game object class, bullets, scenery, items you name it the factory
will be able to spawn it. The object that is returned is chosen at runtime and
is not pre-computed. This means that you can spawn enemies and items on the
fly. Here is a UML design of a factory.
If you would like more information about
the factory design pattern and an example implementation, check out this link.
If you want a playlist of videos
that goes through a lot of object oriented programing design patterns then
check out this link to be taken to a Youtube playlist.
No comments:
Post a Comment