Created
April 18, 2017 07:03
-
-
Save jsscclr/cd3e5ca44f7fc01b69ed071b86b22416 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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. */ | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); } | |
}; | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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_; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
}; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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