game-programming-patterns icon indicating copy to clipboard operation
game-programming-patterns copied to clipboard

Command Pattern bindings

Open crcdng opened this issue 10 months ago • 1 comments

I'm a bit confused about the command pattern implementation.

In the 'input handler code snippet, the command binding is hinted at:

// Methods to bind commands...

private:
  Command* buttonX_;
  Command* buttonY_;
  Command* buttonA_;
  Command* buttonB_;

I think here it would be helpful to show the actual code for the bindings. Because the purpose of the pattern is to enable the re-binding of buttons, it would be useful to show a binding and re-binding in the example.

crcdng avatar Jan 29 '25 13:01 crcdng

Agreed. Here's my suggested bindings:

// Methods to bind commands  

  void bindButtonX(Command* command) { buttonX_ = command; }  
  void bindButtonY(Command* command) { buttonY_ = command; }  
  void bindButtonA(Command* command) { buttonA_ = command; }  
  void bindButtonB(Command* command) { buttonB_ = command; }

Then for testing purposes, I added a fifth method instead of Bob's handleInput() method:

void testEachButton() {
    buttonX_->execute();
    buttonY_->execute();
    buttonA_->execute();
    buttonB_->execute();
  }

To use this, you can do:

   InputHandler inputHandler;

    JumpCommand jumpCommand;
    FireCommand fireCommand;
    SwapWeaponCommand swapWeaponCommand;
    LurchIneffectivelyCommand lurchIneffectivelyCommand;

    // You can add logic here to assign the buttons based on the game's menu settings.
    // For now, here's a set of default bindings for testing purposes
    inputHandler.bindButtonX(&jumpCommand);
    inputHandler.bindButtonY(&fireCommand);
    inputHandler.bindButtonA(&swapWeaponCommand);
    inputHandler.bindButtonB(&lurchIneffectivelyCommand);
    
    inputHandler.testEachButton();

I've tested this and it seems to work. Of course you can add logic at this point to allow the buttons to be assigned according to the user's choices in the game's settings menu.

Here's my entire test program:

#include <iostream>

class Command
{
public:
  virtual ~Command() {}
  virtual void execute() = 0;
};

class JumpCommand : public Command { 
    public: virtual void execute() { std::cout <<"Jump!\n"; } 
}; 

class FireCommand : public Command { 
    public: virtual void execute() { std::cout <<"Fire!\n"; } 
}; 

class SwapWeaponCommand : public Command { 
    public: virtual void execute() { std::cout <<"Swap!\n"; } 
}; 

class LurchIneffectivelyCommand : public Command { 
    public: virtual void execute() { std::cout <<"Lurch!\n"; } 
};

class InputHandler
{
public:

  // Methods to bind commands
  void bindButtonX(Command* command) { buttonX_ = command; }
  void bindButtonY(Command* command) { buttonY_ = command; }
  void bindButtonA(Command* command) { buttonA_ = command; }
  void bindButtonB(Command* command) { buttonB_ = command; }

  void testEachButton() {
    buttonX_->execute();
    buttonY_->execute();
    buttonA_->execute();
    buttonB_->execute();
  }

private:
  Command* buttonX_;
  Command* buttonY_;
  Command* buttonA_;
  Command* buttonB_;
};

int main(int argc, char *argv[]) {
    InputHandler inputHandler;

    JumpCommand jumpCommand;
    FireCommand fireCommand;
    SwapWeaponCommand swapWeaponCommand;
    LurchIneffectivelyCommand lurchIneffectivelyCommand;

    // You can add logic here to assign the buttons based on the game's menu settings.
    // For now, here's a set of default bindings for testing purposes
    inputHandler.bindButtonX(&jumpCommand);
    inputHandler.bindButtonY(&fireCommand);
    inputHandler.bindButtonA(&swapWeaponCommand);
    inputHandler.bindButtonB(&lurchIneffectivelyCommand);

    inputHandler.testEachButton();
}

This will produce the output:

Jump! Fire! Swap! Lurch!

JayParsons avatar Mar 03 '25 15:03 JayParsons