Game Development Reference
In-Depth Information
{
static_cast<OpenChestOption*>(m_openSwordChest.get())->SetChest(&m_swordChest);
m_enemies.emplace_back(CreateEnemy(EnemyType::Dragon));
static_cast<AttackEnemyOption*>(m_attackDragonOption.get())->SetEnemy(m_enemies[0]);
m_enemies.emplace_back(CreateEnemy(EnemyType::Orc));
static_cast<AttackEnemyOption*>(m_attackOrcOption.get())->SetEnemy(m_enemies[1]);
}
The constructor now calls the factory methods to create the proper instances needed to initialize the
shared_ptr
for each
Option
and
Enemy
. Each
Option
has its own pointer, but the
Enemy
instances are
now placed into a vector using the
emplace_back
method. I've done this to show you how you can
use the
shared_ptr::get
method along with
static_cast
to convert the polymorphic base class to
the derived class needed to add the
Enemy
. The same type of cast is needed to add the address of
m_swordChest
to the
m_openSwordChest
option.
That's all there is to creating basic factory functions in C++. These functions come into their own
when writing level loading code. Your data can store the type of object you'd like to create at any
given time and just pass it into a factory that knows how to instantiate the correct object. This
reduces the amount of code in your loading logic, which can help reduce bugs! This is definitely a
worthwhile goal.
Decoupling with the Observer Pattern
The observer pattern is very useful in decoupling your code. Coupled code is code that shares too
much information about itself with other classes. This could be specific methods in its interface or
variables that are exposed between classes. Coupling has a couple of major drawbacks. The first
is that it increases the number of places where your code must be updated when making changes
to exposed methods or functions and the second is that your code becomes much less reusable.
Coupled code is less reusable because you have to take over any coupled and dependent classes
when deciding to reuse just a single class.
Observers help with decoupling by providing an interface for classes to derive which provide
event methods that will be called on objects when certain changes happen on another class. The
Event
system introduced earlier had an informal version of the observer pattern. The
Event
class
maintained a list of listeners that had their
HandleEvent
method called whenever an event they were
listening for was triggered. The observer pattern formalizes this concept into a
Notifier
template
class and interfaces that can be used to create observer classes. Listing 23-6 shows the code for
the
Notifier
class.
Listing 23-6. The
Notifier
Template Class
template <typename Observer>
class Notifier
{
private:
using Observers = std::vector<Observer*>;
Observers m_observers;