객체의 내부 상태에 따라 스스로 행동을 변경할 수 있게 허가하는 패턴으로, 이렇게 하면 객체는 마치 자신의 클래스를 바꾸는 것처럼 보입니다.(GoF의 디자인 패턴 395p)
캐릭터의 상태들을 클래스로 분리해서 특정 이벤트가 발생하면 상태가 전환되어 그 상태를 캐릭터가 가지도록 하는 기법이다.

#include <iostream>
using namespace std;
enum Input {
RELEASE_DOWN,
PRESS_B,
PRESS_DOWN
};
enum Graphic {
IMAGE_STAND,
IMAGE_DUCK
};
class C_Hero_State {
public:
virtual ~C_Hero_State() {}
virtual shared_ptr<C_Hero_State> Handle_Input(C_Hero& hero, Input input) {}
virtual void Update(C_Hero& hero) {}
virtual void Enter(C_Hero& hero) {}
};
class C_On_Ground_State : public C_Hero_State {
public:
virtual shared_ptr<C_Hero_State> Handle_Input(C_Hero& hero, Input input) override {
if (input == PRESS_B) {
return make_shared<C_Jumping_State>();
}
else if (input == PRESS_DOWN) {
return make_shared<C_Ducking_State>();
}
}
};
class C_Standing_State : public C_On_Ground_State {
public:
virtual void Enter(C_Hero& hero) override {
hero.Set_Graphics(IMAGE_STAND);
}
//다른 코드들
};
class C_Ducking_State : public C_On_Ground_State {
public:
C_Ducking_State() :charge_time_(0) {}
virtual void Enter(C_Hero& hero) override {
hero.Set_Graphics(IMAGE_DUCK);
}
virtual shared_ptr<C_Hero_State> Handle_Input(C_Hero& hero, Input input) override{
if (input == RELEASE_DOWN){
return make_shared<C_Standing_State>();
}
else {
C_On_Ground_State::Handle_Input(hero, input);
}
}
virtual void Update(C_Hero& hero) override {
++charge_time_;
if (charge_time_ > MAX_CHARGE) {
hero.Super_Bomb();
}
}
private:
static const int MAX_CHARGE = 10;
int charge_time_;
};
class C_Jumping_State : public C_Hero_State {
//생략
};
class C_Hero {
public:
void Handle_Input(Input input);
void update() {
state_->Update(*this);
}
void Set_Graphics(Graphic graphic) {}
void Super_Bomb() {}
private:
shared_ptr<C_Hero_State> state_;
shared_ptr<C_Hero_State> equipment_;
};
void C_Hero::Handle_Input(Input input)
{
auto state = state_->Handle_Input(*this, input);
if (state)
{
state.reset();
state = nullptr;
state_ = state;
state_->Enter(*this);
}
auto equipment = equipment_->Handle_Input(*this, input);
if (equipment)
{
equipment.reset();
equipment = nullptr;
equipment_ = equipment;
equipment_->Enter(*this);
}
}