본문 바로가기

unity3d

Unity3D에서 C# Script로 FSM (Finite State Machine) 구현

1. FSM 구현을 위해 Unity3D engine 이 제공하는 StartCoroutine 메서드 활용.

Unity > Support > Script Reference > MonoBehaviour.StartCoroutine 참고

Unity3D engine 에서 제공하는 MonoBehaviour 객체의 StartCoroutine 메서드는 매 프레임 마다 지정 된 콜백함수를 실행합니다.

Debug.Log 를 찍어서 확인 해 보시면, Update, StartCoroutine 에서 지정 된 콜백함수 순으로 실행이 됩니다.

이때 지정 된 콜백 함수가 IEnumerator 를 반환하는 형태이기 때문에 while 문과 yield 키워드를 통해 FSM 을 구현 할 수 있습니다.

 

2. State 정의 및 IEnumerator 를 반환하는 State 별 함수 구현.

  - State 정의

    우선, FSM 이 되는 객체에 State 를 정의 합니다. (귀찮아서 세밀하게 구현 하는 것보단 심플하게 어떻게 동작하는지 보여드리는게 더 효과적일 것 같아서 Init, Idle, Move 로만 정의했습니다.)

 

public enum DudeState {
    Init,
    Idle,
    Move
}

 

  - State 별 함수 구현

    FSM을 구현하기 위해 3가지의 메서드가 필요합니다. (State 최초 진입 시 실행 될 메서드, 매 프레임마다 실행 될 메서드, State 종료시 실행 될 메서드)

    만약, StartCoroutine 메서드가 없다면 각 메서드를 구현 해 주고, State 변경 메서드를 따로 두어 관리해야 하겠지만, Unity3D engine 을 사용 시에는 더욱 더 편하게 3개의 메서드를 하나로 통합 할 수 있으며, 클래스 상속을 통해 메서드를 상속, 오버라이드 하여 유연하게 구현하는 장점이 생기죠.

방법은 다음과 같습니다.

 

IEnumerator MoveState() {
    // Enter
    this.gameObject.animation.Play("Take 001");
    yield return null;

    while (this.State == DudeState.Move) {
        // Excute
        this.gameObject.transform.position +=
            new Vector3(0, 0, Time.deltaTime * moveSpeed);

        if (!moving) {
            this.State = DudeState.Idle;
        }

        yield return null;
    }

    // Exit
    NextState();
}

 

    IEnumerator 를 반환하고 yield 키워드를 사용하는 이유는 이렇습니다.

    StartCoroutine에 콜백함수가 지정되면, 지정 된 콜백함수는 매프레임마다 Update 문 다음에 실행됩니다. 이 때, yield 문을 만나면 콜백함수 내에서 yield 다음 구문을 다음 프레임으로 양보하고 콜백함수가 종료가 됩니다. 그러면 또 다음번 프레임에서는 yield 문 다음 구문이 실행이 되는 것이죠.

 

    그래서 위와 같이 콜백함수를 코딩하면,

      - State 최초 진입 시 실행 되는 블럭 (Enter 부분, while 문 이전까지)

      - 매 프레임 마다 실행 되는 블럭 (Execute 부분, While 문 블럭)

      - State 종료 시 실행 되는 블럭 (Exit 부분, while문 블럭 이하)

    이렇게 구현이 되는 것이죠.

 

3. 각 State 에 맞는 StartCoroutine 의 콜백함수(2.번에서 구현 된)를 지정.

 

protected void NextState() {
    string methodName = State.ToString() + "State";
    System.Reflection.MethodInfo info = GetType().GetMethod(methodName,
        System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
    StartCoroutine((IEnumerator)info.Invoke(this, null));
}

 

 

 

 

요약

1. FSM 구현을 위해 Unity3D engine 이 제공하는 StartCoroutine 메서드 활용.

2. State 정의 및 IEnumerator 를 반환하는 State 별 함수 구현.

3. 각 State 에 맞는 StartCoroutine 의 콜백함수(2.번에서 구현 된)를 지정.

 

 

 

Unity 샘플 프로젝트를 첨부합니다.

FSMSample.7z