상태 패턴은 전략 패턴과 유사하게 행동을 캡슐화 시켰다는 점에서 유사하다.
하지만 전략 패턴과 다르게 상태 패턴은 객체 내부 상태에 따라 행동이 바뀌고, 상태가 서로 전환된다는 점에 집중한다
#include <iostream>
#include <Windows.h>
#include <time.h>
using namespace std;
class IState;
class IdleState;
class WalkState;
class RunState;
class AttackState;
class Player
{
IState* state;
public:
inline IState* GetState() { return state; }
void ChangeState(IState* changeState);
};
enum class EKeyCode
{
Walk,
Sprint,
Attack,
};
#pragma region State
class IState
{
public:
virtual void EnterState(Player* player) = 0;
virtual void HandleInput(Player* player, EKeyCode inputKey) = 0;
virtual void Update(Player* player) = 0;
};
class IdleState : public IState
{
public:
void EnterState(Player* player) override;
void HandleInput(Player* player, EKeyCode inputKey) override;
void Update(Player* player) override;
};
class WalkState : public IState
{
public:
void EnterState(Player* player) override;
void HandleInput(Player* player, EKeyCode inputKey) override;
void Update(Player* player) override;
};
class RunState : public IState
{
public:
void EnterState(Player* player) override;
void HandleInput(Player* player, EKeyCode inputKey) override;
void Update(Player* player) override;
};
class AttackState : public IState
{
public:
void EnterState(Player* player) override;
void HandleInput(Player* player, EKeyCode inputKey) override;
void Update(Player* player) override;
};
#pragma endregion
#pragma region State_Cpp
void IdleState::EnterState(Player* player)
{
cout << "Idle 상태 진입" << endl;
}
void IdleState::HandleInput(Player* player, EKeyCode inputKey)
{
switch (inputKey)
{
case EKeyCode::Walk:
cout << "걸어가기 시작합니다." << endl;
player->ChangeState(new WalkState());
break;
case EKeyCode::Sprint:
cout << "달리기 시작합니다" << endl;
player->ChangeState(new RunState());
break;
case EKeyCode::Attack:
cout << "공격합니다" << endl;
player->ChangeState(new AttackState());
break;
}
}
void IdleState::Update(Player* player)
{
cout << "가만히 있습니다." << endl;
}
//==============================================================================
void WalkState::EnterState(Player* player)
{
cout << "Walk 상태 진입" << endl;
}
void WalkState::HandleInput(Player* player, EKeyCode inputKey)
{
switch (inputKey)
{
case EKeyCode::Walk:
cout << "이미 걷는 중입니다." << endl;
break;
case EKeyCode::Sprint:
cout << "달리기 시작합니다" << endl;
player->ChangeState(new RunState());
break;
case EKeyCode::Attack:
cout << "걷기를 멈추고 공격합니다" << endl;
player->ChangeState(new AttackState);
break;
}
}
void WalkState::Update(Player* player)
{
cout << "걷고있습니다." << endl;
}
//==============================================================================
void RunState::EnterState(Player* player)
{
cout << "Run 상태 진입" << endl;
}
void RunState::HandleInput(Player* player, EKeyCode inputKey)
{
switch (inputKey)
{
case EKeyCode::Walk:
cout << "다시 걷기 시작합니다." << endl;
player->ChangeState(new WalkState());
break;
case EKeyCode::Sprint:
cout << "이미 달리는 중입니다." << endl;
break;
case EKeyCode::Attack:
cout << "달리기를 멈추고 공격합니다." << endl;
player->ChangeState(new AttackState());
break;
}
}
void RunState::Update(Player* player)
{
cout << "달리고 있습니다!!" << endl;
}
//==============================================================================
void AttackState::EnterState(Player* player)
{
cout << "Attack 상태 진입" << endl;
}
void AttackState::HandleInput(Player* player, EKeyCode inputKey)
{
switch (inputKey)
{
case EKeyCode::Walk:
cout << "공격 중이라 못 걷습니다." << endl;
break;
case EKeyCode::Sprint:
cout << "공격 중이라 달리지 못합니다." << endl;
break;
case EKeyCode::Attack:
cout << "공격을 중지합니다." << endl;
player->ChangeState(new IdleState());
break;
}
}
void AttackState::Update(Player* player)
{
cout << "공격 중입니다." << endl;
}
#pragma endregion
void Player::ChangeState(IState* changeState)
{
if (state) delete state;
state = changeState;
}
int main()
{
Player* player = new Player();
player->ChangeState(new IdleState());
while (true)
{
Sleep(1000);
srand(time(NULL));
int random = rand() % 3;
player->GetState()->HandleInput(player, (EKeyCode)random);
player->GetState()->Update(player);
cout << endl << endl;
}
return 0;
}