2015년 4월 15일 수요일

Finite State Machine for CSharp_Step1. FSM 구현

Explain. 
유한 상태 기계라고 하며, 특정한 Input(event) 에 따라 해당하는 state(output)으로 변화하는 방법론. 다양한 분야(특히 게임)에 사용되어 지고있으며 상태에 변화에 따른 이벤트를 발생시킬수있으므로 좀더 유연한 로직을 구성할수있다. 이전에 게임 제작시 사용했던 현재도 사용하고있는 FSM에 대해 정리. 스크립트 설명의경우 주석으로 진행.

Step. 
1. FiniteStateMachine 구현
2. 간단한 사용법

FSM 구현

Summary.
 IState ( FiniteState의 명세를 담은 Interface )
 FiniteState ( State 클래스 )
 FiniteStateMachine ( FSM 클래스 )

IState.cs

interface IState<T>
{
    
    void Enter();
    void Excute();
    void Exit();

    T _StateID
    {
        get;
    }
}

FiniteState.cs
class FiniteState<T, U> : IState<U>
{
    protected T entity;

    public virtual void SetEntity(T entity)
    {
        this.entity = entity;
    }

    public virtual void Enter()
    {
        Console.WriteLine(typeof(T).ToString() + "Enter");
    }

    public virtual void Excute()
    {
        Console.WriteLine(typeof(T).ToString() + "Excute");
    }

    public virtual void Exit()
    {
        Console.WriteLine(typeof(T).ToString() + "Exite");
    }

    public virtual U _StateID
    {
        get
        {
            throw new ArgumentException("Exception");
        }
    }

}

FiniteStateMachine.cs
class FiniteStateMachine<T, U>
{
    private T entity; // State의 주체가 되는 class

    private Dictionary<U, FiniteState<T, U>> stateDic; // 전체 State

    private FiniteState<T, U> currentState; // 현재 상태
    private FiniteState<T, U> previousState; // 이전 상태

    /// <summary>
    /// 생성자
    /// </summary>
    /// <param name="entity">주체 class</param>
    public FiniteStateMachine(T entity)
    {
        this.entity = entity;
        stateDic = new Dictionary<U, FiniteState<T, U>>();
    }

    public void ExcuteState()
    {
        if (currentState != null) currentState.Excute();
    }

    public void ChangeState(FiniteState<T, U> nextState)
    {
        if (currentState == nextState) return;

        if(currentState != null)
        {
            currentState.Exit();
            previousState = currentState;
        }

        currentState = nextState;

        currentState.Enter();
    }

    public void ChangeState(U stateID)
    {
        try
        {
            FiniteState<T, U> state = stateDic[stateID];
            ChangeState(state);
        }
        catch(KeyNotFoundException)
        {
            // exception 처리
        }
    }

    //이전 state로 상태 되돌리기
    public void RevertState()
    {
        if (previousState != null)
            ChangeState(previousState);
    }

    public void AddState(FiniteState<T, U> state)
    {
        if (state == null) return;
        state.SetEntity(entity);
        stateDic.Add(state._StateID, state);
    }

    public void RemoveState(FiniteState<T, U> state)
    {
        stateDic.Remove(state._StateID);
    }
}

0 개의 댓글:

댓글 쓰기