SendMessage로 FSM 구현해보기 (Unity3D)
# Introduce
FSM을 구현하기 위해 State Pattern을 다뤄보던 중,
SendMessage를 이용하여 기존 사용하던 FSM을 더 가독성 좋게 구현하게 되어서 공유하려 합니다.
FSM?
FSM 은 유한 상태 기계(Finite State Machine)를 의미합니다.
유한 상태 기계는 말 그대로 유한한 수의 상태를 가진 기계를 이야기 하는데요.
다음과 같은 특징을 지닙니다.
- 유한 상태 기계는 유한한 수의 상태들을 가진다.
- 그 중 반드시 하나의 상태만 취한다.
- 현재 상태는 특정 조건이 되면 다른 상태로 변할 수 있다.
- 유한 상태 기계는 가능한 상태들의 집합과 각 상태들의 전이 조건으로 정의될 수 있다.
- 상태들을 그래프로 표현이 가능하다.

# Pros & Cons
장점
- 구현이 간단하다.
- 직관적이다.
- 원하는 함수들만 구현할 수 있다.
단점
- 규모가 커진다면 설계가 복잡해진다.
- 구조가 단순한 만큼 예측이 가능하다.
- SendMessage의 비용
장점은 매우 간단합니다.
기본적인 FSM의 장점들을 모두 가져오며 추가로 원하는 항목의 함수들만 구현하면 되기 때문에 코드 가독성은 더 좋아지게 됩니다.
단점으로는 기본적인 FSM의 단점들과 추가로 SendMessage의 비용이 부담되는데,
유니티의 SendMessage는 런타임 중 리플렉션을 통해 함수 호출하는 게 아니라 함수명을 String 형태로 Map으로 관리하기 때문에
일반적으로 아는 SendMessage만큼 느리진 않다고는 하지만
어찌되었든 직접 클래스 내에서 호출 하는 것 보다는 무거울 것이 확실하기 때문입니다.
# For example
#region FSM_Declare // FSM 선언부 private bool _isNewState; // 상태가 변해야 하는지 알려주는 변수 private enum STATE { Idle, Chase, Flee } // 상태들 선언. 해당 상태들은 상태명 뒤에 Enter,Update,Exit을 붙여 함수화됩니다. private STATE _State = STATE.Idle; // 현재 상태 변수 // 상태를 변경할 때 호출합니다. private void SetState(STATE state) { _isNewState = true; _State = state; } // FSM을 루프시키는 이터레이터입니다. private IEnumerator FSM() { while (true) { _isNewState = false; yield return StartCoroutine(FSM_State(_State)); } } // 현재 상태의 함수를 호출해주는 이터레이터입니다. (ex. IdleEnter(), IdleUpdate(), IdleExit()) private IEnumerator FSM_State(STATE state) { SendMessage(string.Format("{0}Enter", state), SendMessageOptions.DontRequireReceiver); do { yield return null; if (_isNewState) { SendMessage(string.Format("{0}Exit", state), SendMessageOptions.DontRequireReceiver); yield break; } SendMessage(string.Format("{0}Update", state), SendMessageOptions.DontRequireReceiver); } while (!_isNewState); SendMessage(string.Format("{0}Exit", state), SendMessageOptions.DontRequireReceiver); } #endregion
FSM에 꼭 필요한 변수와 함수들을 선언하는 구역입니다.
SetState() 함수를 통해 상태 변경을 할 수 있습니다.
상태가 변할때마다 FSM() 에서 FSM_State() 코루틴을 실행하게 되고,
FSM_State() 에서 현재 상태의 Enter, Update, Exit 함수를 SendMessage를 통해 호출합니다.
#region FSM_Implement // FSM 구현부. 상태명 + Enter, Update, Exit 으로 구현합니다. // 필요한 경우에만 구현하면 됩니다. 필요하지 않다면 함수조차 구현하지 않아도 무관합니다. private void IdleEnter() { Debug.Log("Idle Start"); } private void IdleUpdate() { Debug.Log("Idle Update"); } private void IdleExit() { Debug.Log("Idle Start"); } #endregion
FSM의 상태를 구현하는 구역입니다.
SendMessage(DontRequireReceiver)를 통해 호출 하기 때문에 필요한 상태의 필요한 함수만 구현할 수 있습니다.
예를 들어, IdleUpdate() 함수는 필요하지만 IdleEnter(), IdleExit()이 필요하지 않다면 구현하지 않아도 괜찮습니다.
단, 위에서 선언한 열거형 STATE의 상태들과 동일한 이름을 사용해야 합니다.
# Epilogue
FSM을 코루틴과 SendMessage로 최대한 간단히 구현해 보았습니다.
간단한 AI나 상태 패턴을 구현할 때 도움이 되셨으면 좋겠습니다.
감사합니다.
# Refrences
'개발 > Design Pattern' 카테고리의 다른 글
Command Pattern (0) | 2022.01.24 |
---|---|
Singleton (0) | 2022.01.14 |
댓글을 사용할 수 없습니다.