Game Development Reference
In-Depth Information
if (pOption != nullptr)
{
pOption->Evaluate(m_player);
}
}
};
The
EvaluateListener::OnVisit
method uses a
dynamic_cast
to determine if the supplied
visitable
variable is an object derived from the
Option
class. If it is, the
Option::Evaluate
method is called.
The only remaining update is to use the
EvaluateVisitor
class to interface with the chosen option in
Game::EvaluateInput
. This update is shown in Listing 23-19.
Listing 23-19. The
Game::EvaluateInput
Method
void Game::EvaluateInput(stringstream& playerInputStream)
{
PlayerOptions chosenOption = PlayerOptions::None;
unsigned int playerInputChoice{ 0 };
playerInputStream >>playerInputChoice;
try
{
Option::Pointer option =
m_player.GetCurrentRoom()->EvaluateInput(playerInputChoice);
EvaluateVisitor evaluator{ m_player };
option->Visit(evaluator);
}
catch (const std::out_of_range&)
{
cout << "I do not recognize that option, try again!" << endl << endl;
}
}
As you can see, the code has been updated to call the
Visit
method on the
Option
rather than
calling the
Evaluate
method directly. That's all we needed to do to add the
Visitor
pattern to the
Text Adventure game.
This example isn't the best use of the
Visitor
pattern, as it is relatively simple. Visitors can come
into their own in places such as a render queue in 3-D games. You can implement different types of
rendering operations in
Visitor
objects and use that to determine how individual games render their
3-D objects. Once you get the hang of abstracting out logic in this way, you might find many places
where being able to provide different implementations independently of the data is very useful.
Summary
This chapter has given you a brief introduction to the concept of design patterns. Design patterns
are exceptionally useful as they provide a ready-made toolbox of techniques that can be used to
solve many diverse problems. You've seen the
Singleton
,
Factory
,
Observer
, and
Visitor
patterns
used in this topic, but there are many, many more.