Skip to content

Instantly share code, notes, and snippets.

@jsscclr
Created April 18, 2017 07:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jsscclr/cd3e5ca44f7fc01b69ed071b86b22416 to your computer and use it in GitHub Desktop.
Save jsscclr/cd3e5ca44f7fc01b69ed071b86b22416 to your computer and use it in GitHub Desktop.
class Command {
public:
virtual ~Command();
virtual void Execute() = 0;
protected:
Command();
};
// game programming patterns
class Command
{
public:
virtual ~Command() {}
virtual void execute() = 0;
};
class Command
{
public:
virtual ~Command() {}
virtual void execute(GameActor& actor) = 0;
};
class Command
{
public:
virtual ~Command() {}
virtual void execute() = 0;
virtual void undo() = 0;
};
/* To create a command that calls Action on an instance of class MyClass, a client simply writes */
MyClass* receiver = new MyClass;
// ...
Command* aCommand =
new SimpleCommand<MyClass>(receiver, &MyClass::Action);
// ...
aCommand->Execute();
/* Keep in mind that this solution only works for simple commands.
More complex commands that keep track of not only their receivers
but also arguments and/or undo state require a Command subclass. */
void InputHandler::handleInput()
{
if (isPressed(BUTTON_X)) jump();
else if (isPressed(BUTTON_Y)) fireGun();
else if (isPressed(BUTTON_A)) swapWeapon();
else if (isPressed(BUTTON_B)) lurchIneffectively();
}
class InputHandler
{
public:
void handleInput();
// Methods to bind commands...
private:
Command* buttonX_;
Command* buttonY_;
Command* buttonA_;
Command* buttonB_;
};
void InputHandler::handleInput()
{
if (isPressed(BUTTON_X)) buttonX_->execute();
else if (isPressed(BUTTON_Y)) buttonY_->execute();
else if (isPressed(BUTTON_A)) buttonA_->execute();
else if (isPressed(BUTTON_B)) buttonB_->execute();
}
Command* InputHandler::handleInput()
{
if (isPressed(BUTTON_X)) return buttonX_;
if (isPressed(BUTTON_Y)) return buttonY_;
if (isPressed(BUTTON_A)) return buttonA_;
if (isPressed(BUTTON_B)) return buttonB_;
// Nothing pressed, so do nothing.
return NULL;
}
Command* command = inputHandler.handleInput();
if (command)
{
command->execute(actor);
}
Command* handleInput()
{
Unit* unit = getSelectedUnit();
if (isPressed(BUTTON_UP)) {
// Move the unit up one.
int destY = unit->y() - 1;
return new MoveUnitCommand(unit, unit->x(), destY);
}
if (isPressed(BUTTON_DOWN)) {
// Move the unit down one.
int destY = unit->y() + 1;
return new MoveUnitCommand(unit, unit->x(), destY);
}
// Other moves...
return NULL;
}
class JumpCommand : public Command
{
public:
virtual void execute() { jump(); }
};
class JumpCommand : public Command
{
public:
virtual void execute(GameActor& actor)
{
actor.jump();
}
};
class FireCommand : public Command
{
public:
virtual void execute() { fireGun(); }
};
/* A MacroCommandmanages a sequence of subcommands and provides operations for adding and removing subcommands.
No explicit receiver is required, because the subcommands already define their receiver. */
class MacroCommand : public Command {
public:
MacroCommand();
virtual ~MacroCommand();
virtual void Add(Command*);
virtual void Remove(Command*);
virtual void Execute();
private:
List<Command*>* _cmds;
};
/* The key to the MacroCommand is its Execute member function.
This traverses all the subcommands and performs Execute on each of them. */
void MacroCommand::Execute () {
ListIterator<Command*> i(_cmds);
for (i.First(); !i.IsDone(); i.Next()) {
Command* c = i.CurrentItem();
c->Execute();
}
}
/* Note that should the MacroCommand implement an Unexecute operation,
then its subcommands must be unexecuted in reverse order relative to Execute’s implementation.
Finally, MacroCommand must provide operations to manage its subcommands.
The MacroCommand is also responsible for deleting its subcommands. */
void MacroCommand::Add (Command* c) {
_cmds->Append(c);
}
void MacroCommand::Remove (Command* c) {
_cmds->Remove(c);
}
class MoveUnitCommand : public Command
{
public:
MoveUnitCommand(Unit* unit, int x, int y)
: unit_(unit),
x_(x),
y_(y)
{}
virtual void execute()
{
unit_->moveTo(x_, y_);
}
private:
Unit* unit_;
int x_, y_;
};
class MoveUnitCommand : public Command
{
public:
MoveUnitCommand(Unit* unit, int x, int y)
: unit_(unit),
xBefore_(0),
yBefore_(0),
x_(x),
y_(y)
{}
virtual void execute()
{
// Remember the unit's position before the move
// so we can restore it.
xBefore_ = unit_->x();
yBefore_ = unit_->y();
unit_->moveTo(x_, y_);
}
virtual void undo()
{
unit_->moveTo(xBefore_, yBefore_);
}
private:
Unit* unit_;
int xBefore_, yBefore_;
int x_, y_;
};
function makeMoveUnitCommand(unit, x, y) {
// This function here is the command object:
return function() {
unit.moveTo(x, y);
}
}
function makeMoveUnitCommand(unit, x, y) {
var xBefore, yBefore;
return {
execute: function() {
xBefore = unit.x();
yBefore = unit.y();
unit.moveTo(x, y);
},
undo: function() {
unit.moveTo(xBefore, yBefore);
}
};
}
/*
OpenCommand opens a document whose name is supplied by the user.
An OpenCommand must be passed an Application object in its constructor.
AskUser is an implementation routine that prompts the user for the name of the document to open.
*/
class OpenCommand : public Command {
public:
OpenCommand(Application*);
virtual void Execute();
protected:
virtual const char* AskUser();
private:
Application* _application;
char* _response;
};
OpenCommand::OpenCommand (Application* a) {
_application = a;
}
void OpenCommand::Execute () {
const char* name = AskUser();
if (name != 0) {
Document* document = new Document(name);
_application->Add(document);
document->Open();
}
}
/*
A PasteCommand must be passed a Document object as its receiver.
The receiver is given as a parameter to PasteCommand’s constructor.
*/
class PasteCommand : public Command {
public:
PasteCommand(Document*);
virtual void Execute();
private:
Document* _document;
};
PasteCommand::PasteCommand (Document* doc) {
_document = doc;
}
void PasteCommand::Execute () {
_document->Paste();
}
/*
For simple commands that aren’t undoable and don’t require arguments,
we can use a class template to parameterize the command’s receiver.
We’ll define a template subclass SimpleCommand for such commands.
SimpleCommand is parameterized by the Receiver type and
maintains a binding between a receiver object and an action stored as a pointer to a member function.
*/
template <class Receiver>
class SimpleCommand : public Command {
public:
typedef void (Receiver::* Action)();
SimpleCommand(Receiver* r, Action a) :
_receiver(r), _action(a) {}
virtual void Execute();
private:
Action _action;
Receiver* _receiver;
};
/* The constructor stores the receiver and
the action in the corresponding instance variables.
Execute simply applies the action to the receiver. */
template <class Receiver>
void SimpleCommand<Receiver>::Execute () {
(_receiver->*_action)();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment