반응형
GoF 디자인 패턴에서의 명령 패턴에 대한 정의는 "요청 자체를 캡슐화하는 것입니다. 이를 통해 요청이 서로 다른 사용자를 매개변수로 만들고, 요청을 대기시키거나 로깅하며, 되돌릴 수 있는 연산을 지원합니다"라고 써있다. 이는 매우 복잡하고 난해하게 써있다고 생각한다.
간단하게 정의하면 콜백을 객체지향적으로 표현한 것이라고 한다.
A, B, X, Y키가 존재하는 게임기에 대해 Input Handler를 구현해보자
void InputHandler::handleInput()
{
if(isPressed(BUTTON_X)) jump();
else if(isPressed(BUTTON_Y)) Swap();
else if(isPressed(BUTTON_A)) fireGun();
else if(isPressed(BUTTON_B)) Run();
}
입력 키에 대한 변경이 없다면 문제가 없겠지만, 많은 게임에서는 키 세팅을 변경할 수 있도록 지원한다.
키 변경을 위해서라면 jump()와 같이 직접적인 함수 호출이 아닌 다른 방식으로 구현해야한다.
이를 위해 게임 행동을 나타내는 객체를 제작한다.
class Command
{
public:
virtual ~Command() {}
virtual void execute() = 0; //상속을 위한 함수이기에 순수 가상함수로 제작
}
행동을 나타내는 Command 객체를 기반으로 행동을 나타내는 클래스를 제작한다.
class JumpCommand : public Command
{
public:
virtual void execute() { jump(); }
};
class FireCommand : public Command
{
public:
virtual void execute() { fireGun(); }
};
그리고 Command 클래스에 맞춰 InputHandler를 수정한다
class InputHandler
{
public:
void HandleInput();
private:
Command* button_X;
Command* button_Y;
Command* button_A;
Command* button_B;
};
void InputHandler::handleInput()
{
if(isPressed(BUTTON_X)) button_X->execute();
else if(isPressed(BUTTON_Y)) button_Y->execute();
else if(isPressed(BUTTON_A)) button_A->execute();
else if(isPressed(BUTTON_B)) button_B->execute();
}
아래와 같은 방식을 통하여 플레이어 뿐이 아닌 GameActor에 대한 모든 객체에 사용하도록 제어할 수 있다.
class JumpCommand : public Command
{
public:
virtual void execute(GameActor& actor)
{
actor.jump();
}
};
Command* InputHandler::handleInput()
{
if(isPressed(BUTTON_X)) button_X;
if(isPressed(BUTTON_Y)) button_Y;
if(isPressed(BUTTON_A)) button_A;
if(isPressed(BUTTON_B)) button_B;
return NULL;
}
//Example
Command* command = inputHandler.handleInput();
if(command)
{
command->execute(actor);
}
반응형