개요
별게임에 나오는 모든 오브젝트는 다음과 같은 상태를 가질 수 있습니다.
1. 자석 아이템을 먹었을때의 상태
2. 거인 아이템을 먹었을때의 상태
3. 코인으로 변화시키는 아이템을 먹었을 때의 상태
4. 별로 변화시키는 아이템을 먹었을 때의 상태
위 4개의 상태는 공존할 수 있습니다.(3번 4번은 서로 공존할 수 없다.)
즉, 플레이어가 거인인 상태에서 자석을 먹고 모든 bullet이 코인으로 변화되는 아이템을 먹을 수 있다는 것입니다.
위와 같은 복잡한 상황을 구현하기 위해 FSM과 State를 도입하였습니다.
먼저 FSM(stateMachine)의 코드는 다음과 같습니다.
(가독성을 위해 적당히 편집하였습니다.)
FSM 코드
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | /*------------------------CStateMachine------------------------ * Template 클래스 * FSM사용을 원하는 클래스에서 정의하여 사용할 수 있다. * 사용자는 States를 가지고 있어야 한다. * Global, Current, Previous 상태를 가지고 있다. --------------------------------------------------------------*/ /* template으로 정의됨 */ template <class T> /* 생성 시 FSM을 사용하고자하는 객체의 This를 넘겨 받는다. */ CStateMachine(T* Owner) /* 현재 상태를 전달받은 상태로 변경한다. * 현재 상태는 이전상태에 저장한다. * 현재상태의 Exit함수를 호출하며 새로운 생태의 Enter함수를 호출한다. */ template <class T> void CStateMachine<T>::ChangeState(CState<T>* pNewState) { if (m_pCurrentState != nullptr) m_pCurrentState->Exit(m_pOwner); m_pPreviousState = m_pCurrentState; m_pCurrentState = pNewState; m_pCurrentState->Enter(m_pOwner); } /* 현재 상태와 Global상태를 Execute */ template <class T> void CStateMachine<T>::Execute(float delta) const { if (m_pGlobalState != nullptr) m_pGlobalState->Execute(m_pOwner, delta); if (m_pCurrentState != nullptr) m_pCurrentState->Execute(m_pOwner, delta); } /* FSM을 사용하고자 하는 주체 */ T* m_pOwner; /* Previous 상태는 직전의 상태를 보관한다. * Current에 들어있는 상태를 실행한다. * Global은 어떠한 상황에서도 가장 먼저 반영된다. */ CState<T>* m_pPreviousState; CState<T>* m_pCurrentState; CState<T>* m_pGlobalState; | cs |
CStateMachine<T> 클래스의 주요 함수 및 동작원리 설명
1. 유한 상태 머신 디자인 패턴으로 구현되어 있습니다.
2. Generic Programming 을 위한 Template으로 정의 되어있습니다.
3. ChangeState에서 이전 상태의 후 처리 함수를 호출하고 새로운 상태의 전처리 상태를 호출하면서 변경합니다.
4. 오브젝트의 AI를 상태머신으로 관리하고 싶을때 Component로 정의하면됩니다.
FSM 사용 예 ( Player의 FSM )
1 | CStateMachine<CPlayer>* m_FSM; | cs |
1. 플레이어의 AI를 FSM으로 관리하기 위해 정의
2. Player::Execute에서 FSM의 Execute 실행
3. Player의 AI상태를 실행 및 변경 합니다.
아래는 위 FSM 이 관리하는 State 추상클래스입니다.
State 코드
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | /*---------------------------CState---------------------------- * Template 클래스 * FSM을 소유하는 클래스의 상태를 정의하는 추상클래스 * State의 인터페이스만을 제공한다. * 각 함수는 모두 FSM의 주체 인스턴스를 인자로 받는다. --------------------------------------------------------------*/ /* template으로 정의됨 */ template <class T> /* Enter()은 상태가 Execute를 실행하기 전에 한번만 호출된다. */ virtual void Enter(T* pOwner) = 0; /* Execute()은 상태의 메인 루프이다. */ virtual void Execute(T* pOwner, float delta) = 0; /* Exit()은 상태가 종료 혹은 변경될 때 한번만 호출된다. */ virtual void Exit(T* pOwner) = 0; | cs |
1. 위의 FSM이 관리하는 State들의 인터페이스 클래스입니다.(추상클래스)
2. 어떤 오브젝트이든 상태를 가질 수 있도록 template으로 정의하였습니다.
3. 전처리를 위한 Enter, 반복 실행을 위한 Execute, 후처리를 위한 Exit으로 구성되어 있습니다.
사용 예(Player의 상태 중 1개)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | class CPlayerNormal : public CState<CPlayer>{ public: static CPlayerNormal* Instance(); /* 상태 전 처리 */ void Enter(CPlayer* player) {} void Execute(CPlayer* player, float delta) { /* 현재 플레이어가 거인 아이템을 먹었다면 */ if(eITEM_FLAG_giant & CItemManager::Instance()->getCurrentItem()) { /* 거인 아이템을 먹은 상태로 상태 변경 */ player->getFSM()->ChangeState(CPlayerGiant::Instance()); } } /* 상태 후 처리 */ void Exit(CPlayer* player) {} private: CPlayerNormal(){} virtual ~CPlayerNormal(){} } | cs |
1. CPlayerNormal은 플레이어 클래스의 상태 중 하나입니다.
2. 주체로써 Player의 인스턴스를 전달합니다
귀차니즘을 위한 3줄 요약
1. 게임의 상태표현을 위해 FSM구현
2. Stage, Player, Bullet은 상태를 가진다.
3. 각각의 상태는 Ente, Execute, Exit의 상태를 가진다.
'All > Project' 카테고리의 다른 글
UI_ MyButton (0) | 2016.04.12 |
---|---|
별게임의 상태트리 (0) | 2016.04.12 |
Shooter / Bullet (0) | 2016.04.12 |
ObjectManager (0) | 2016.04.12 |
PoolingManager (0) | 2016.04.12 |