개요

별게임에 나오는 모든 오브젝트는 다음과 같은 상태를 가질 수 있습니다.

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

+ Recent posts