TIL(Today I Learned) 병행 상태 머신

2025. 5. 2. 22:25[Unity] Game Programing

병행 상태 머신 – Unity 게임 개발을 중심으로

✍️ 오늘 학습할 내용

병행 상태 머신(Parallel State Machine)의 개념과 이론을 알아보고, Unity 엔진을 활용한 게임 개발 맥락에서 병행 상태 머신을 어떻게 구현하고 활용할 수 있는지 살펴보겠습니다.

 

먼저 UML 및 컴퓨터 과학 측면에서 병행 상태 머신의 이론적 정의를 깊이 있게 설명한 후, Unity 엔진을 이용한 실무 구현 방법들(예: ScriptableObject 기반 FSM, Behaviour Tree, 계층형 FSM 등)을 구조도, 코드 예시, 장단점 비교와 함께 다룹니다.

 

마지막으로 한국, 일본, 영어권에서 공개된 사례나 오픈소스 라이브러리를 조사하여 실제로 병행 상태 머신이 게임 개발에 어떻게 사용되고 있는지 살펴보고, 개인적으로 배우게 된 점과 느낀 점을 정리합니다.

1. 병행 상태 머신의 이론적 개념

병행 상태 머신(Parallel State Machine)은 하나의 객체나 시스템이 동시에 여러 상태를 가질 수 있도록 한 상태 모델링 개념입니다. 일반적인 유한 상태 머신(FSM)은 한 시점에 하나의 상태(state)만 활성화되지만, 병행 상태 머신에서는 독립적인 하위 상태머신(영역, region)이 여러 개 존재하여 병렬로 활성 상태를 유지할 수 있습니다.

 

이 개념은 UML 상태 다이어그램(스테이트차트)에서 orthogonal state 혹은 병렬 구성 상태로 정의되며, 컴퓨터 공학 및 소프트웨어 설계 분야에서 복잡한 동작의 동시성(concurrency)을 모델링하기 위해 활용됩니다.

 

또한 GoF의 상태 패턴(State Pattern)을 응용하여 구현할 수 있는 병행 상태 관리 방법으로도 이해할 수 있습니다.

학습 요약

병행 상태 머신의 이론적 토대를 이해하기 위해, 먼저 전통적 상태 머신과 상태 패턴의 개념을 정리하고, 이어서 상태 다이어그램에서의 병렬 상태, 즉 동시성 상태가 무엇인지 알아보겠습니다.

 

일반 FSM은 하나의 현재 상태와 이벤트에 따른 전이로 구성되지만, 병행 상태 머신에서는 여러 개의 상태 그룹이 동시에 활성화될 수 있습니다. UML에서는 이를 동시 상태(Concurrent States) 또는 직교 상태(Orthogonal States)라고 부르며, Harel의 Statechart에서 처음 도입된 개념입니다.

 

이러한 병렬 상태 구조를 통해 복잡한 시스템의 다른 측면(예: 애니메이션과 AI, 물리와 UI 등)을 독립적인 상태 기계로 나눠 관리할 수 있습니다.

 

이를 구현하는 소프트웨어 설계 기법으로는 상태 패턴을 확장하거나, 여러 FSM 인스턴스를 병렬 실행하는 방법 등이 있으며, 이론적으로는 상태들의 데카르트 곱을 통한 합성으로 이해할 수도 있습니다.

 

요약하면, 병행 상태 머신은 “여러 개의 상태 머신을 병렬로 운영하여 한 객체의 여러 상태 차원을 동시에 표현”하는 개념입니다.

 

사례 분석

병행 상태 머신의 개념은 아래 그림의 UML 상태 다이어그램 예시로 시각화할 수 있습니다.

 

 

이 다이어그램은 “경매(Auction)” 프로세스를 나타내며, 상위 상태 Auction 내부에 두 개의 병행 **하위 상태 영역**(위: 입찰 처리, 아래: 결제 승인)이 있음을 보여줍니다.

 

상위 상태에 진입하면 두 영역이 동시에 활성화되어 각각 Getting Bid → Evaluating → Accepting (입찰 처리 흐름)과 Checking → Authorized (결제 한도 확인 흐름)이 병렬로 진행됩니다.

 

각 영역은 별도의 시작 지점(●)과 종료 상태(◎)를 가지며, 두 흐름이 모두 완료되어야 전체 Auction 프로세스가 완료됩니다.

 

이처럼 병행 상태 머신을 사용하면 시스템이 **동시에** 두 가지 일을 수행할 수 있는 상태를 자연스럽게 표현할 수 있습니다.

 

한 영역에서 이벤트(예: 입찰 완료)가 발생해도 다른 영역(결제 승인 절차)에 영향을 주지 않고 독립적으로 처리되며, 상위 상태는 모든 병행 상태가 종료될 때 비로소 완료(transitions to final state)됩니다.

 

이를 통해 상태 모델을 병렬화함으로써 복잡한 동작을 분리 정복할 수 있습니다.

 

UML의 또 다른 예로 전자 시계의 동작을 생각해보겠습니다.

 

시계는 “시간 표시”와 “라디오 재생”이라는 두 측면의 상태를 동시에 가질 수 있습니다.

 

하나의 병행 상태 머신으로 시계를 모델링하면, 상위 상태 “On(켜짐)” 아래에 Display 영역(현재 시간 표시 vs 알람 시간 표시)과 Audio 영역(라디오 재생 vs CD 재생)이 나뉘어져 존재합니다.

 

시계가 켜지면 두 영역의 초기 상태(예: 현재시간 표시 & 라디오 재생)가 동시에 활성화되고, 사용자는 시간 표시 모드와 오디오 모드를 독립적으로 전환할 수 있습니다.

 

이 경우 “라디오→CD 전환” 등의 이벤트는 Audio 영역의 상태에만 영향을 주고, Display 영역에서는 “현재시간↔알람시간 표시” 상태를 그대로 유지합니다.

 

이러한 **직교 상태** 구성은 하나의 객체(시계)가 실질적으로 두 가지 상태 조합(시간 표시 상태, 오디오 상태)을 동시에 갖게 함으로써 복합적인 행동을 단순화합니다.

 

병행 상태가 없다면, 시계의 모든 상태 조합을 단일 FSM으로 만들어야 하며 “현재-라디오”, “현재-CD”, “알람-라디오”, “알람-CD” 등 4가지 조합 상태와 여러 전이를 만들어야겠지만, 병행 FSM을 쓰면 두 영역 각각 2개씩 상태만으로도 동일한 상황을 표현할 수 있습니다.

 

즉, 병행 상태 머신은 **상태의 조합 폭발 문제**(state explosion)를 효과적으로 억제해주는 모델링 기법입니다.

 

개인적인 인사이트

병행 상태 머신 개념을 학습하면서 얻은 핵심 인사이트는 “복잡한 시스템일수록 상태를 한 곳에 몰아두기보다 적절히 **분할(orthogonalization)** 해서 병렬로 관리하는 것이 유리하다”는 점입니다.

 

예를 들어 게임 캐릭터를 생각하면, 전통 FSM으로는 ‘이동 중인지 공격 중인지’ 등 모든 조합 상태를 하나의 거대한 FSM으로 관리해야 할 수도 있습니다.

 

그러나 병행 상태 머신 개념을 도입하면 “이동 상태” FSM과 “공격 상태” FSM을 분리하여 캐릭터가 동시에 이동하고 공격하는 상황을 자연스럽게 표현할 수 있습니다.

 

이는 구현상의 이점뿐만 아니라 설계와 사고의 복잡도를 줄여줍니다.

 

하나의 상태 기계로 모든 것을 표현하려고 하면 새로운 상태가 추가될 때마다 기하급수적으로 상태와 전이가 늘어나지만, 병행 구조로 나누면 각각의 FSM이 독립적으로 작동하면서도 필요한 최소한의 상호작용(예: 특정 상태 완료 신호나 공통 이벤트)에 의해서만 서로 영향을 주게 할 수 있습니다.

 

이러한 구조적인 이점은 UML의 정형적인 모델링 뿐만 아니라 실무 코드 구현에서도 동일하게 적용된다고 느꼈습니다.

 

실제로 상태 패턴을 사용한 객체 지향 설계에서도, 필요하다면 객체 내에 여러 상태 구성을 가진 서브 상태 머신들을 운용함으로써 병행 상태를 표현할 수 있음을 알게 되었습니다.

 

나아가 병행 상태 머신 개념은 단순히 여러 작업을 동시에 처리한다는 의미를 넘어, **관심사의 분리**(Separation of Concerns)를 상태 설계에 접목한 사례라는 점이 인상적이었습니다.

 

각 병행 영역은 서로 다른 책임(Responsibility)을 가지며, 이렇게 나눠진 상태들은 병렬로 존재하지만 서로 간섭 없이 자기 역할을 수행합니다.

 

이는 잘 설계된 소프트웨어 모듈처럼 상태 기계에도 모듈화를 적용하는 셈이며, 복잡한 AI나 게임 로직을 관리하는 데 매우 효과적이라는 깨달음을 얻었습니다.

 

2. Unity에서의 병행 상태 머신 구현 방법

이제 이론적으로 살펴본 병행 상태 머신 개념을 **Unity 게임 개발** 실무에서는 어떻게 활용할 수 있는지 알아보겠습니다.

 

Unity 엔진에서는 다양한 AI나 게임 오브젝트의 동작 제어에 상태 머신 패턴이 사용됩니다.

 

Unity에서 상태 머신을 구현하는 대표적인 방법으로는

 

1. 간단한 **유한 상태 머신(FSM)** 구현 (예: enumswitch 문 활용)

2. **ScriptableObject**를 활용한 플러그형 FSM 아키텍처

3. **행동 트리(Behavior Tree)** 활용

4. **계층형 FSM (HFSM)** 구조

 

등이 있습니다.

 

각각 접근 방식마다 장단점이 있으며, 특히 병행 상태를 다루는 방법에 차이가 있습니다.

 

이하에서는 Unity를 중심으로 이러한 구현 방식들을 설명하고, 병행 상태를 표현하거나 여러 FSM을 병렬로 운용하는 패턴에 대해 구체적으로 살펴보겠습니다.

 

학습 요약

Unity에서 FSM을 구현하는 방식은 크게 코드 중심과 에디터/데이터 중심으로 나눌 수 있습니다.

 

코드 중심 방식은 MonoBehaviour 스크립트에서 Update 루프 등을 이용해 현재 상태를 체크하고 전환하는 것으로, 소규모 FSM에 적합합니다.

 

데이터 중심 방식은 Unity의 **ScriptableObject****Animator** 등 에디터 활용을 통해 상태와 전환을 자산(asset)으로 정의하여 유연성을 높이는 것입니다.

 

또한 복잡한 AI 로직을 구현할 때는 FSM만으로는 한계가 있으므로, Behavior Tree와 같은 계층적/병렬 구조를 갖춘 AI 기법이 쓰입니다. Unity에서는 Mecanim 애니메이터가 이미 병행 상태(레이어)를 지원하는 FSM의 한 예이며, AI에서는 Behavior Tree 플러그인이나 커스텀 FSM 프레임워크를 활용해 병행 처리 로직을 구현합니다.

 

이 섹션에서는 간단한 FSM 구현에서 점차 발전시켜 ScriptableObject 기반 FSM, Behavior Tree, HFSM 순으로 살펴보고, 각 방법이 병행 상태를 표현하는 데 어떻게 활용되는지 요약합니다.

 

2.1 기본 FSM 구현 (MonoBehaviour 기반)

가장 단순한 방식은 **MonoBehaviour** 스크립트 내에서 FSM을 코딩하는 것입니다.

 

Unity Update 메서드에서 현재 상태에 따라 행동을 수행하고, 특정 조건이 되면 다른 상태로 전이시킵니다.

 

예를 들어, 적 캐릭터의 AI를 FSM으로 구현한다고 하면, 상태를 나타내는 enum과 switch문을 활용하여 아래와 같이 작성할 수 있습니다.

// 간단한 Unity FSM 예제 (MonoBehaviour)
public class EnemyController : MonoBehaviour {
    private enum State { Patrol, Chase, Attack }
    private State currentState = State.Patrol;
    
    void Update() {
        switch (currentState) {
            case State.Patrol:
                Patrol();
                // 플레이어 발견 시 상태 전이
                if (DetectPlayer()) {
                    currentState = State.Chase;
                }
                break;
            case State.Chase:
                Chase();
                // 사정거리 이내면 공격 상태로
                if (InAttackRange()) {
                    currentState = State.Attack;
                }
                // 놓쳤으면 다시 순찰로
                else if (!DetectPlayer()) {
                    currentState = State.Patrol;
                }
                break;
            case State.Attack:
                Attack();
                // 플레이어가 도망가면 추격 상태로
                if (!InAttackRange()) {
                    currentState = State.Chase;
                }
                break;
        }
    }
}

위 코드는 전형적인 유한 상태 머신의 형태를 띠고 있습니다.

State enum으로 정의된 상태들 간에 currentState를 바꿔가며 동작합니다.

 

이러한 구현은 간단한 경우에는 충분하지만, 상태와 전이가 많아질수록 switch 문이 복잡해지고 유지보수가 어려워집니다.

 

또한 이 구조에서는 **병행 상태**를 직접적으로 표현하기 어렵습니다. 예를 들어 “순찰하면서 경계 태세”와 같이 두 상태를 동시에 가지는 상황을 표현하려면, 새로운 복합 상태를 만들거나 두 FSM 스크립트를 따로 관리해야 합니다.

 

기본적인 MonoBehaviour FSM 구현은 빠르게 prototyping하기 좋지만, 확장성 면에서 한계가 있고 상태의 **모듈화****병렬화**를 지원하지 않기 때문에 복잡한 AI에는 부적합합니다.

 

2.2 ScriptableObject 기반 플러그형 FSM

Unity에서는 **ScriptableObject**를 이용하여 FSM을 보다 데이터 주도적으로 구현하는 패턴이 널리 알려져 있습니다.

 

ScriptableObject는 에디터에서 생성할 수 있는 오브젝트 자산으로, 게임 오브젝트에 붙지 않고 독립적으로 데이터와 로직을 보관할 수 있습니다.

 

이 특성을 이용해 상태(State), 행동(Action), 전이(Transition)를 각각 ScriptableObject로 만들고, Inspector에서 조합함으로써 유연한 FSM을 구현하는 방식이 있습니다.

 

흔히 “플러그어블 FSM” 혹은 “Pluggable AI” 기법이라고 불리며, Unity 공식 튜토리얼과 여러 게임 AI 샘플에서 사용된 패턴입니다.

 

이 구조에서는 각 상태가 자신만의 행동 로직과 전이 조건을 가지고 독립적인 객체로 존재하므로, 상태를 **재사용**하거나 **여러 오브젝트에 공유**하기도 쉽습니다.

 

아래는 ScriptableObject FSM의 주요 요소를 나타낸 코드 구조 예시입니다:

// State ScriptableObject 정의 예시
[CreateAssetMenu(menuName = "PluggableFSM/State")]
public class State : ScriptableObject {
    public Action[] actions;       // 이 상태에서 매 프레임 실행할 액션들
    public Transition[] transitions; // 이 상태에서 체크할 전이들

    public void UpdateState(StateController controller) {
        // 매 프레임 액션 실행
        foreach (Action act in actions) {
            act.Act(controller);
        }
        // 전이 조건 체크
        foreach (Transition trans in transitions) {
            if (trans.condition.Evaluate(controller)) {
                controller.TransitionToState(trans.targetState);
                break;
            }
        }
    }
}

위 코드에서 State는 ScriptableObject로, 내부에 액션 리스트와 전이 리스트를 가지고 있습니다.

 

StateController (MonoBehaviour로 게임오브젝트에 부착)에서 매 프레임마다 현재 상태의 UpdateState()를 호출하면, 해당 상태가 액션들을 수행하고 전이 조건을 검사하여 상태 전환을 일으킵니다.

 

ActionCondition 역시 추상 클래스로 정의된 ScriptableObject이고, 각각 Act(), Evaluate() 메서드를 구현하여 구체적 로직을 담습니다.

 

예를 들어 PatrolAction, ChaseAction 등이 Action을 상속받아 구현될 수 있습니다.

 

이러한 구조에서는 새로운 상태나 행동을 추가하려면 ScriptableObject 자산을 만들고 Inspector에서 연결만 하면 되므로, **확장성****유연성**이 높습니다.

 

또한 한 ScriptableObject 상태를 여러 오브젝트의 FSM에서 참조할 수 있으므로(예: 여러 적 캐릭터가 공유하는 “공격” 상태 등), 게임 전역적으로 상태 로직을 일관성 있게 관리할 수 있습니다.

 

병행 상태를 ScriptableObject FSM으로 구현하는 방법의 하나는 **여러 개의 상태 머신을 병렬로 운영**하는 것입니다.

 

예를 들어 앞서 이론 파트에서 소개한 마리오의 예를 적용해 보면, 마리오 캐릭터에 두 개의 StateController를 붙여서 하나는 “크기/파워업” 상태를 관리하고, 다른 하나는 “버프(스타맨 무적 등)” 상태를 관리하게 할 수 있습니다.

 

실제 Unity 튜토리얼에서도 마리오에 대해 이러한 이중 FSM을 사용했는데, 하나는 Small/Super/Fire/Dead와 같은 기본 폼을 관리하고, 다른 하나는 Invincible(무적) 버프 상태를 관리했습니다.

 

두 FSM은 서로 독립적으로 작동하면서 병렬 상태를 구현합니다.

 

Small 마리오가 스타(power-up)를 먹으면 기본 폼 FSM은 Small->Super로 전이하고, 버프 FSM은 Default->Invincible로 전이하여 둘 다 동시에 마리오 객체에 영향을 주는 식입니다.

 

이처럼 ScriptableObject FSM을 활용하면, 굳이 하나의 거대한 상태 머신에 병행 구조를 구현하지 않더라도 여러 FSM 컴포넌트를 오브젝트에 부여함으로써 **사실상의 병행 상태 관리**가 가능합니다. 이는 Unity 컴포넌트 시스템의 장점을 살린 접근이라고 할 수 있습니다.

 

 

*위 그림은 ScriptableObject 기반 FSM으로 구현된 마리오의 상태 다이어그램 예시입니다.

 

마리오는 기본적으로 Small/Super/Fire Mario 등의 상태를 가질 수 있고, 별도의 FSM으로 Invincible(무적) 상태를 병렬로 관리합니다.

 

파란색 상태(예: Small Mario)들은 마리오의 크기/형태에 대한 FSM이고, 노란색 상태(Invincible)는 별도의 버프 FSM입니다. 빨간색으로 표시된 이벤트(예: damaged)는 상태 전이를 촉발하며, 두 FSM이 병행으로 운용되어 마리오 객체의 복합 상태를 구성합니다. (출처: Unity Pluggable AI 튜토리얼 예제)*

 

ScriptableObject FSM의 장점은 **디자인과 튜닝의 용이성**입니다.

 

게임 디자이너나 밸런스 담당자가 코드를 수정하지 않고 Inspector에서 상태 전환 조건이나 행동을 조정할 수 있습니다.

 

또한 상태와 행동이 자산으로 분리되어 있으므로, 여러 객체 간에 논리를 공유하거나 플레이 중 동적으로 상태 자산을 교체하는 등 유연한 응용도 가능합니다.

 

단점으로는 초기 설계와 구현이 복잡하며, 작은 규모의 FSM에는 오히려 과도한 구조일 수 있다는 점입니다.

 

또한 Unity 에디터 의존성이 있기 때문에 순수 코드에 비해 성능 오버헤드(함수 호출, ScriptableObject 관리)가 약간 있으며, 아주 복잡한 병행 상태 (예: 3개 이상의 동시 상태)를 하나의 FSM으로 표현하려면 기본 패턴을 확장해야 하는 한계가 있습니다.

 

그럼에도 불구하고 ScriptableObject FSM 패턴은 **유지보수성****재사용성** 면에서 뛰어나서 중간 규모 AI에 널리 사용되고 있습니다.

 

2.3 행동 트리(Behavior Tree)

행동 트리는 현대 게임 AI에서 FSM을 대체하거나 보완하는 중요한 기법입니다.

 

행동 트리는 계층적 트리 구조로 의사결정을 표현하며, **Selector**, **Sequence**, **Decorator** 등의 노드를 이용해 복잡한 행동을 모듈화합니다.

 

FSM과의 큰 차이점 중 하나는 행동 트리가 병렬 실행(Parallel 노드)을 자연스럽게 지원한다는 것입니다.

 

Behavior Tree에서는 특정 노드 타입으로 여러 하위 행동을 동시에 실행하거나 특정 조건 하에 병행 평가할 수 있습니다.

 

예를 들어, BT에서는 “이동하면서 공격” 같은 동시 행동을 병렬 노드를 통해 구현할 수 있으며, 각 하위 브랜치의 성공/실패 조건에 따라 트리가 판단을 내립니다.

 

FSM으로 동일한 동작을 만들려면 여러 상태 조합을 일일이 작성해야 하겠지만, BT에서는 트리 구조상 둘을 독립적인 노드로 표현하여 병행성을 부여하는 것이 가능합니다.

 

Unity에서 행동 트리를 활용하려면 직접 구현하거나 에셋 스토어의 플러그인을 사용할 수 있습니다.

 

Behavior Tree 구현은 Tick(갱신) 메서드를 재귀적으로 돌면서 노드들을 평가하는 방식으로 이뤄집니다.

 

간단히 말해, 루트 노드부터 시작해 자식 노드들을 순서대로(또는 병렬로) 실행하고, 조건 노드는 현재 월드 상태를 체크하며, Action 노드는 실제 캐릭터 동작을 수행합니다.

 

Behavior Tree는 **조건부 결정****행동 실행**이 한 구조 안에 통합되어 있어, 상태와 트랜지션을 명시적으로 구분하던 FSM과 사고방식이 다릅니다.

 

특히 병행 상태에 대해서는, FSM이 “둘 이상의 상태를 동시에 취한다”는 방식을 택하는 반면, BT는 “둘 이상의 행동 노드를 동시에 실행시킨다”는 차이가 있습니다.

 

결과적으로 표현력 측면에서 BT는 복잡한 AI 로직, 특히 상위 목표를 분해하고 동시 조건을 처리하는 데 탁월합니다.

 

Unity의 대표적 BT 구현 예로 **플레이메이커(PlayMaker)****Behavior Designer** 같은 상용 에셋, 또는 오픈소스 **Panda BT**, **NodeCanvas** 등이 있습니다.

 

Unity 2018+ 버전에서는 시각적 스크립팅(볼트/Bolt 등)과 결합해 커스텀 BT를 제작하기도 하고, ML-Agents에서 학습된 정책을 Behavior Tree 노드로 감싸 사용하는 경우도 있습니다.

 

Behavior Tree를 사용하는 Unity 프로젝트의 예로는 Ubisoft의 게임 AI(디비전 등)나, 국내 사례로 넥슨의 모바일 MMORPG ‘로열 블러드’ 개발에서 FSM 대신 Behavior Tree로 복잡한 이벤트 시스템을 구현한 사례가 보고되었습니다.

 

이러한 사례들은 복잡한 캐릭터 행동 제어에 FSM보다 BT가 더 적합한 경우를 보여줍니다.

 

Behavior Tree의 시각화된 트리는 디버깅과 조정에 유리하며, 트리의 일부 가지(branch)를 쉽게 수정하거나 재활용할 수 있어 대규모 AI에 자주 채택됩니다.

 

다만 Behavior Tree도 만능은 아니어서, 단순한 상태 전환만 필요한 경우에는 FSM보다 이해하기 어렵거나 비대해질 수 있습니다.

 

또한 트리가 깊어지면 디버깅이 어려워지는 단점도 있어, 실제로는 FSM과 BT를 혼합한 하이브리드 구조도 쓰입니다.

 

예를 들어, 상위 레벨의 전략 결정은 BT로 하고, 하위 동작(모션 제어 등)은 FSM으로 하는 식입니다. Unity 개발 시에도 Animator 같은 것을 FSM로 쓰면서, BT 노드에서 애니메이터 상태를 제어하는 경우가 많습니다.

 

결국 중요한 것은 문제의 특성에 맞는 도구를 선택하는 것인데, Behavior Tree는 **복잡한 의사결정과 병행 행동**에 장점을 보이므로, 적 AI나 동적 시나리오 연출 등에 많이 활용되는 추세입니다.

 

2.4 계층형 FSM (HFSM)과 병렬 구조

계층형 FSM(HFSM)은 FSM의 상태를 계층으로 조직화하여 큰 상태를 여러 하위 상태로 나누는 개념입니다.

 

이는 Harel Statechart의 또 다른 요소로, 병행 상태와 함께 계층적 상태(서브머신) 개념을 도입함으로써 FSM의 복잡도를 다루는 방법입니다.

 

Unity에서는 애니메이션용 상태머신(Animator)에서 **Sub-State Machine** 개념으로 HFSM을 직접 지원합니다.

 

Animator에서 하나의 상태를 다시 하위 상태 머신(여러 클립으로 구성)으로 정의할 수 있는데, 예를 들어 “Locomotion”이라는 상위 상태를 두고 그 안에 “Idle/Walk/Run” 등의 하위 상태들을 둘 수 있습니다.

 

게임 로직 FSM에서도 계층 구조를 수동으로 구현할 수 있습니다. 예를 들어, 캐릭터 AI를 “전투 상태”와 “비전투 상태”로 크게 나누고, 전투 상태 안에서는 다시 “근접전투 FSM”과 “원거리전투 FSM”을 운용하는 식입니다.

 

이렇게 하면 공통 로직(전투→비전투 전환 등)은 상위에서 처리하고, 세부 로직은 하위 FSM들이 담당하게 되어 구조가 정돈됩니다.

 

HFSM에서 병행 상태를 다루는 방법은 두 가지입니다.

 

첫째, 계층형 구조 안에서도 각 레벨에서 병행 영역을 도입하는 것입니다(일부 상태는 병행, 일부는 순차).

 

UML statechart에서는 계층+병행을 혼합할 수 있듯이, 실무에서도 상위 FSM 두 개를 병렬로 돌리고, 그 각각이 계층을 가질 수 있습니다.

 

둘째, 계층 FSM과는 별도로, **여러 FSM 컴포넌트**를 붙여 병행 실행하는 것입니다.

 

사실 이 두 번째 방법은 앞서 ScriptableObject FSM에서 이미 논의한 내용과 겹치는데, Unity에서는 컴포넌트를 다수 붙일 수 있으므로 자연스럽게 여러 FSM을 계층 없이 병렬 구동할 수 있습니다.

 

예를 들어 플레이어 캐릭터에 “상태 FSM”과 “모션 FSM” 두 개를 붙여서, 상태 FSM은 게임 플레이 논리(생존/사망, 모드 등)를 다루고 모션 FSM은 애니메이션(걷기/달리기/공격 동작)을 담당하게 할 수 있습니다.

 

이렇게 분리하면 둘이 병렬로 움직이며, 모션 FSM은 애니메이터와 연동되고 상태 FSM은 게임 이벤트와 연동되어 서로 다른 영역을 관리합니다.

 

Unity의 Mecanim Animator는 HFSM과 병행 상태 개념을 모두 활용한 사례라고 볼 수 있습니다.

 

Animator Controller에는 여러 **레이어(Layer)**를 둘 수 있는데, 각 레이어는 독립된 상태 머신이며, 기본적으로 병렬로 동작합니다.

 

예컨대 Base Layer는 캐릭터의 하체 동작(이동, 점프 등)을 관리하고, Upper Body Layer는 상체 동작(공격, 조준 등)을 관리하여, 한 캐릭터가 달리면서 동시에 사격할 수 있게 합니다.

 

Animator 레이어 간에는 가중치나 마스크를 통해 애니메이션을 블렌딩하며, 논리적으로는 병행 FSM과 동일합니다. 또한 각 레이어 내에서는 서브 상태머신(HFSM)이 쓰여 복잡한 애니메이션을 계층적으로 관리합니다.

 

이는 Unity 엔진 자체에 병행 FSM 개념이 녹아든 좋은 예시로, 개발자는 비교적 직관적으로 병행 상태를 다룰 수 있습니다.

 

2.5 FSM vs Behavior Tree vs HFSM: 장단점 비교

기법 장점 단점 병행 상태 표현
단순 FSM
(MonoBehaviour)
구현이 쉽고 성능 부담이 적음.
작은 규모에서는 빠른 개발 가능.
상태/전이가 증가하면 복잡도 급증.
상태 간 의존관계가 높아지며 수정 어려움.
기본적으로 병행 상태 지원 없음.
별도 FSM 두 개를 수동으로 동작시키는 식으로 우회 가능.
ScriptableObject FSM
(플러그형)
상태/액션의 재사용성 높음.
디자이너 친화적 튜닝 (데이터 드리븐).
구조적 설계로 유지보수 용이.
설계/학습곡선 높음.
초기 구현 복잡.
잦은 ScriptableObject 호출로 약간의 오버헤드.
복수 FSM 구성으로 병행 구현 용이.
한 FSM 내 병행구조는 커스텀 개발 필요.
Behavior Tree
(행동 트리)
복잡한 AI 로직 표현에 강력.
병렬 수행, 중단, 재시도 등 제어 용이.
시각화 툴로 디버깅 용이.
간단 로직에는 비효율적 (과한 구조).
트리가 커지면 이해 어려움.
일반 프로그래머에겐 FSM보다 생소할 수 있음.
Parallel 노드 등으로 노드 단위 병행 지원.
여러 BT를 동시에 돌리는 것도 가능 (에이전트별 BT).
HFSM
(계층형 FSM)
상태를 계층으로 그룹화하여 복잡도 관리.
공통 동작을 상위 상태에서 처리 (중복 감소).
계층 설계 잘못되면 오히려 혼란.
상태 추가 시 계층 구조 수정 필요.
계층 자체는 병행 아님 (동시는 상위-하위 관계).
다만 병행영역과 혼합 가능 (UML statechart 지원).

위 표는 Unity 엔진 맥락에서 FSM, ScriptableObject 기반 FSM, Behavior Tree, HFSM의 특성을 요약한 것입니다.

 

병행 상태 표현 측면에서 보면, 기본 FSM은 지원이 없고, ScriptableObject FSM은 **다중 FSM 운영**으로 사실상의 병행을 이끌어낼 수 있으며, Behavior Tree는 **병렬 노드** 기능으로 병행 실행을 표현하고, HFSM은 병행이라기보다는 구조화를 통해 복잡도를 줄여주는 방식임을 알 수 있습니다.

 

대체로, **게임플레이 캐릭터 상태**(예: 마리오의 폼 체인지 등)는 FSM/ScriptableObject FSM으로 잘 다룰 수 있고, **적 AI**처럼 복잡한 의사결정은 Behavior Tree가 적합하며, **애니메이션** 제어에는 Unity Animator의 HFSM/병행 구조를 활용하는 식으로 영역별로 적절한 방법을 쓰는 것이 일반적입니다.

 

사례 분석

Unity에서 병행 상태 머신 개념이 어떻게 쓰이는지 이해를 돕기 위해, 앞서 언급한 예시들을 조금 더 구체적으로 살펴보겠습니다.

 

첫 번째 사례는 **Unity Animator**입니다.

 

Unity Animator는 캐릭터 애니메이션을 상태 머신으로 제어하는 도구로, 개발자는 Animator 창에서 상태와 전이를 정의합니다.

 

Animator의 특징 중 하나는 여러 **레이어**로 상태 머신을 구성할 수 있다는 점인데, 이는 실질적으로 상태 머신들을 병렬로 실행하는 것입니다.

 

예를 들어 3인칭 슈팅 게임에서 Base Layer에는 이동, 점프 등의 전체 몸동작을 담고, 두 번째 레이어에는 상체 동작(총 쏘기 등)을 담아, 두 레이어를 “동기화” 옵션 없이 병렬 재생하면 캐릭터가 달리는 동안 상체는 쏘는 애니메이션을 재생할 수 있습니다.

 

Unity는 레이어간 마스크로 상/하체를 분리 적용하도록 해두어, 병행 동작 시에도 애니메이션이 섞이지 않고 깔끔하게 동작합니다.

 

Animator의 Any State나 StateMachineBehaviour 스크립트 기능 등도 FSM 기능을 보강해주지만, 핵심은 **레이어를 통한 병렬 FSM 운용**이 복잡한 캐릭터 애니메이션을 손쉽게 관리하게 한다는 것입니다.

 

이 사례는 게임플레이 로직이 아닌 애니메이션 영역이지만, 병행 상태 머신의 장점을 보여주는 실용 예라 할 수 있습니다.

 

두 번째 사례는 **플러그형 FSM을 사용한 AI**입니다.

 

Unity의 공식 튜토리얼 “Pluggable AI with ScriptableObjects”에서는 적 AI를 구현하면서 상태, 행동, 결정(조건)을 ScriptableObject로 만들고, 여러 적이 이를 공유해서 쓰도록 구성했습니다.

 

이 튜토리얼에서 병행 상태가 직접 등장하지는 않지만, 앞서 언급한 대로 Mario 예제처럼 FSM을 두 개 붙이면 쉽게 병행 상태가 도입될 수 있습니다.

 

특히 ScriptableObject FSM 구조에서는 StateController (MonoBehaviour)가 각자 동작하므로, 한 GameObject에 StateController 컴포넌트를 여러 개 붙여두면 다수의 FSM이 독립적으로 병행 실행됩니다.

 

Unity 컴포넌트 시스템의 자연스러운 병렬성(여러 컴포넌트는 각자 Update를 가짐)을 이용하는 셈입니다.

 

이런 접근은 FSM을 “관심사별로 여러 개” 두는 것으로 생각할 수 있습니다. 예를 들어 **FPS 게임의 플레이어 캐릭터**를 생각해보면, 하나의 FSM으로 무기사용 상태(총기 장전, 사격, 재장전 등)를 관리하고, 별개 FSM으로 이동 상태(걷기, 달리기, 앉기 등)를 관리하며, 또 다른 FSM으로 플레이어의 상태(정상, 부상, 사망 등)를 관리하는 식으로 분리할 수 있습니다.

 

이렇게 3개의 FSM이 한 객체에서 병행하면, 플레이어는 ‘달리면서 (이동FSM) 재장전 중이고 (무기FSM) 부상상태인 (상태FSM)’ 식으로 상태 조합이 이루어지죠.

 

단일 거대 FSM보다 각 영역을 독립적으로 개발하고 테스트하기 쉬우며, 필요하면 FSM들 간에 이벤트로 상호작용(예: 부상 상태일 때 이동속도 제한 등)을 넣으면 됩니다.

 

이런 실제 적용 사례는 복잡한 게임 개체를 다룰 때 유용하며, 프로젝트에 따라 적절히 FSM을 분할하는 노하우가 필요합니다.

 

마지막으로 **Behavior Tree 적용** 사례를 들자면, 언리얼 엔진의 탑다운 슈팅 게임에서 적 AI에 Behavior Tree를 사용하는 경우를 생각할 수 있습니다.

 

Unreal의 BT와 BlackBoard 시스템은 병행 태스크 수행에 강점을 가지며, Unity에서도 비슷한 패턴을 적용 가능합니다.

 

예컨대 **Halo** 시리즈의 AI는 FSM의 복잡도로 악명 높았는데, 이를 Behavior Tree로 전환하여 개발 생산성을 높였다는 일화가 있습니다 (Bungie의 개발자들이 GDC에서 공유한 내용).

 

Unity에서도 고난도 AI (예: 전략 게임의 유닛 AI나 팀 전술 AI 등)는 Behavior Tree 또는 유사한 플로우 그래프로 구현하는 경우가 많습니다.

 

Behavior Tree 에디터를 사용하면 디자이너들도 트리를 보며 튜닝하기 좋고, Node 재활용으로 여러 캐릭터에 공통 AI 루틴을 줄 수도 있습니다.

 

병행 수행은 BT의 기본 제공 기능이므로, 복수의 행동을 동시에 해야 하는 상황을 BT로 자연스럽게 다룰 수 있다는 점이 FSM 대비 큰 장점으로 인식되고 있습니다.

 

최근에는 Unity ECS/DOTS 환경에서 Job 시스템과 BT를 결합하여 다수의 NPC를 효율적으로 업데이트하거나, Behavior Tree 노드를 Burst 컴파일하여 성능을 끌어올리는 시도 등도 이뤄지고 있습니다.

 

이처럼 Behavior Tree는 “복잡성과 병행성이 높은 AI”의 대표 솔루션으로 자리잡아 가고 있습니다.

 

개인적인 인사이트

Unity 엔진에서 다양한 상태 머신 기법을 적용해본 경험을 되돌아보면, **한 가지 기법에 집착하기보다 문제에 맞게 적절한 방법을 조합**하는 것이 중요하다는 생각이 듭니다.

 

FSM vs Behavior Tree 논쟁은 오래되었지만, 실제로 둘은 상호 배타적이지 않고 보완적입니다.

 

Unity 프로젝트에서도 간단한 상호작용이나 UI 상태 등은 그냥 FSM으로 충분하며, 플레이어나 적의 모션 제어는 Animator의 상태 머신을 활용하고, 더 고차원적인 AI 의사결정에는 Behavior Tree를 쓰는 식으로 자연스럽게 **혼용**됩니다.

 

병행 상태를 구현할 때도, 꼭 UML의 orthogonal state를 코드로 1:1 구현하지 않아도, Unity의 구조를 이용해 컴포넌트별 FSM 병렬 실행이나 Animator 레이어 등으로 원하는 효과를 얻을 수 있었습니다.

 

개인적으로 ScriptableObject FSM을 보면서 느낀 점은, 처음에는 약간 과해 보이더라도 장기적으로 확장성과 유지보수에 큰 도움이 된다는 것입니다.

 

상태 추가나 변경이 잦은 게임이라면, 차라리 초기부터 데이터 주도 FSM으로 가는 편이 중복 코드를 줄이고 협업도 수월했습니다.

 

반면 아주 단순한 상태기계에 이 패턴을 적용했다가 오히려 개발 시간만 늘어난 경우도 있었는데, 이때 배우게 된 것은 **“필요한 복잡성에 맞는 도구를 선택하라”**는 교훈이었습니다.

 

병행 상태 머신 역시 마찬가지로, 모든 것을 병렬로 만들 필요는 없지만, 동시에 일어나는 여러 상황을 깔끔히 관리해야 할 때 그 가치를 발휘한다고 생각합니다.

 

Unity에서 이를 구현하는 방법이 다양하므로, 각 방법의 트레이드오프를 이해하고 상황에 맞게 선택하는 지혜가 필요하겠습니다.

 

3. 국내외 사례 연구 및 오픈소스 활용

병행 상태 머신 및 관련 FSM/Behavior Tree 기법이 실제 게임 개발 현장에서 어떻게 쓰였는지, 한국과 일본, 그리고 글로벌(영어권) 사례를 살펴보겠습니다.

 

이를 통해 이 개념들이 이론에 그치지 않고 실무에서 어떤 문제를 해결했는지, 그리고 커뮤니티에서 공유되는 지식이나 라이브러리가 무엇이 있는지 파악해보겠습니다.

 

3.1 국내 사례 (한국)

국내 게임 개발에서도 FSM과 Behavior Tree에 관한 관심이 높았으며, 특히 NDC(Nexon Developers Conference)나 각종 세미나에서 관련 발표가 있었습니다.

 

예를 들어, NDC 2018에서는 《모바일 MMO RPG 로열 블러드 사례로 본 복잡한 이벤트 시스템 구현: Behavior Tree 패턴으로 한방에 해결하기》라는 발표가 있었는데, 이 발표에서는 이벤트 처리에 FSM 대신 Behavior Tree를 적용하여 복잡도를 줄이고 개발 효율을 높인 사례를 공유했습니다.

 

요약 자료에 따르면, 다수의 게임 이벤트가 얽힌 시스템을 FSM으로 관리하려다 보니 상태가 급증하고 전이 조건이 꼬이는 문제가 있었는데, 행동 트리로 전환하면서 조건 검사가 트리 구조로 정리되고, 병렬 처리나 우선순위 조건도 손쉽게 표현하여 해결했다고 합니다.

 

이는 병행 상태 머신 자체를 직접 언급한 사례는 아니지만, FSM의 한계를 느낀 실무진이 보다 나은 대안(BT)을 찾아 적용한 좋은 예입니다.

 

또 다른 사례로는 넥슨의 MMORPG **듀랑고(Durango)**의 AI를 들 수 있습니다. 듀랑고 AI 역시 Behavior Tree를 사용했다는 언급이 있었는데, 이는 공룡과 같은 NPC의 복잡한 행동(탐색, 공격, 도망 등)을 구현하는 데 선택된 것으로 보입니다.

 

듀랑고 개발자들은 “요즘 게임들은 AI 패턴이 다양하기 때문에 대부분 Behavior Tree를 사용할 것”이라고 언급했는데, 이는 곧 FSM만으로 현대적인 AI를 구현하기엔 부족함이 있고, 병행 처리나 계층적 의사결정에 유리한 BT로 업계 트렌드가 옮겨갔다는 의미로 이해됩니다.

 

실제로 국내 대형 게임 프로젝트일수록 FSM보다는 Behavior Tree(또는 Planner, Utility AI 등 고급 기법)를 도입하는 경우가 늘고 있습니다.

 

물론 단순한 FSM 활용 사례도 많습니다.

 

예컨데 인디 게임 개발자나 소규모 모바일게임에서는 ScriptableObject FSM 패턴이 커뮤니티를 통해 전파되어 많이 쓰이고 있습니다.

 

Unity Korea 커뮤니티에서도 ScriptableObject를 이용한 상태 패턴에 대한 논의가 활발했고, 한국어로 된 튜토리얼 및 블로그 포스트도 쉽게 찾아볼 수 있습니다.

 

예를 들어 한 블로그에서는 상태 패턴의 기초와 Unity에서의 구현 방법을 다루며, ScriptableObject를 활용한 예시 코드를 공유하기도 했습니다.

 

이러한 지식 공유를 통해 국내 개발자들도 비교적 쉽게 FSM 아키텍처를 적용하고 병행 상태 개념도 접하게 되었습니다.

 

한편, 국내에서 만들어진 오픈소스 FSM/BT 라이브러리 사례는 드문 편이지만, Unity Asset Store에는 한국 개발자가 만든 FSM 툴이나 Behavior Tree 툴이 올라와 있기도 합니다.

 

다만 글로벌 시장만큼 두드러진 건 없어 보입니다. 요약하면, 한국에서는 **대규모 프로젝트**에서는 Behavior Tree 채택 사례가 늘고 있고 (NDC 등 통해 공유), **중소 규모 프로젝트**에서는 Unity의 ScriptableObject FSM 패턴이 널리 쓰이며, 병행 상태에 대해서는 주로 “여러 FSM 동시 운용”과 “Animator 레이어 활용” 등의 형태로 자연스럽게 구현하고 있다는 것입니다.

 

3.2 일본 사례

일본의 게임 개발 커뮤니티에서도 상태 머신과 Behavior Tree에 대한 관심이 높습니다.

 

일본어로 된 자료를 보면, UML Statechart 및 병행 상태에 대한 개념 정리를 한 블로그 글도 있고, 게임 개발 맥락에서 FSM을 어떻게 개선할지 논의한 글도 보입니다.

 

한 예로, 어떤 일본 개발자는 “게임 오브젝트의 대부분은 유한 오토마톤으로 표현될 수 있다”면서, 게임 개발에 특화된 비(非)튜링 완전한 상태머신 기술을 고안해보자는 내용의 글을 적기도 했습니다.

 

이 글에서는 Unity를 비롯한 기존 엔진들이 상태 머신과 이벤트 간 분업이 잘 안되어 있다는 지적과 함께, 이벤트 주도적인 상태 기술의 가능성을 논했습니다.

 

흥미로운 포인트는, 이 개발자가 병행 상태를 언급하며 “겉보기엔 하나의 오브젝트이지만 확대율과 투명도 같이 전혀 별개의 변화가 있을 수 있으므로, 여러 FSM이 하나의 오브젝트에 작용할 수 있게 하고 싶다”는 뜻을 밝힌 부분입니다.

 

이는 병행 상태 머신의 필요성을 직관적으로 설명한 것으로, 일본 개발자들도 Unity 같은 환경에서 상태를 쪼개 병행 처리하려는 아이디어를 갖고 있음을 보여줍니다.

 

일본에서 만든 대표적인 Unity FSM/BT 도구로 **Arbor**를 들 수 있습니다.

 

Arbor는 일본 Caitsithware에서 개발한 Unity용 시각적 FSM 및 Behavior Tree 에디터입니다.

 

이 툴은 에디터 상에서 그래프 형태로 FSM과 BT를 작성할 수 있게 해주며, 일종의 Visual Scripting 솔루션으로 자리잡았습니다.

 

Arbor를 통해 디자이너들이 직관적으로 상태 전환과 행위를 설계할 수 있고, 프로그래머는 필요한 동작을 스크립트로 추가하여 확장할 수 있습니다.

 

Arbor는 일본뿐 아니라 해외에서도 유저를 확보하여 Asset Store에서 판매되고 있는데, FSM과 Behavior Tree를 동시에 지원하는 점이 특징입니다.

 

즉, 개발자는 상황에 따라 둘 중 편한 방식으로 사용할 수 있고, 심지어 FSM 노드 안에 Behavior Tree를 넣는 등의 복합 구성도 가능합니다.

 

Arbor의 존재는 일본 개발자 커뮤니티가 FSM/BT에 얼마나 관심을 갖고 있는지 보여주는 증거이며, 특히 “간단하고 강력한 FSM & BT 그래프 에디터”라는 문구에서 알 수 있듯이 병행된 상태와 행동을 시각적으로 관리하는 것에 초점을 두고 있습니다.

 

이는 병행 상태 머신 개념을 툴로 실현한 사례라고 볼 수 있습니다.

 

일본 대형 게임 회사들의 구체적인 AI 구현 사례는 외부에 많이 공개되지는 않지만, 일부 CEDEC(일본 게임 개발자 컨퍼런스) 발표에서 단편적으로나마 엿볼 수 있습니다.

 

예를 들어 Capcom이나 Square Enix 등의 엔진에서는 커스텀 FSM/BT 솔루션을 사용한다고 알려져 있습니다.

 

Capcom의 RE엔진 사례로 유추해보면, Resident Evil 시리즈의 좀비 AI 등은 Behavior Tree 형태로 동작하고, 몬스터헌터 시리즈의 몬스터들도 복잡한 패턴을 Behavior Tree로 관리하고 있을 가능성이 큽니다.

 

만약 병행 상태가 필요하다면 BT의 parallel 노드를 쓰거나, FSM+BT 혼합 구조를 쓸 것입니다.

 

일본 개발자들은 전통적으로 자체 엔진을 많이 사용했기 때문에 Unity처럼 범용 솔루션을 쓰는 경우보다는, 개별 프로젝트에 특화된 FSM/BT 프레임워크를 구축해서 사용하는 경우가 많았습니다.

 

이러한 프레임워크에서도 병행 상태 개념은 중요하게 다뤄졌을 텐데, 특히 대전격투 게임이나 액션게임에서 캐릭터의 여러 상태(공격판정, 피격판정, 버프 등)를 병렬로 관리하는 시스템이 있었을 것으로 짐작됩니다.

 

정리하면, 일본에서는 **툴 개발 측면**에서 Arbor와 같은 통합 FSM/BT 에디터가 등장했고, **개념 연구 측면**에서 병행 FSM의 필요성과 표현 방법에 대한 고민이 공유되었으며, **대형 프로젝트 측면**에서는 각사 엔진에서 FSM과 BT를 활용하여 병행적 캐릭터 상태나 AI를 관리해온 것으로 보입니다.

 

일본어로 된 자료들이 비교적 접근성이 낮아 세부 내용을 모두 파악하긴 어렵지만, 핵심은 한국이나 서양과 마찬가지로 **상태 기계의 복잡도 관리와 병행성 문제**에 직면했고, 이를 해결하기 위한 논의와 도구들이 있었다는 점입니다.

 

3.3 영어권 사례 및 오픈소스

영어권에서는 게임 AI에 대한 연구와 사례 공유가 매우 활발합니다.

 

FSM과 Behavior Tree는 오랜 기간 논쟁과 발전을 거쳐왔고, 병행 상태 머신 개념 역시 다양한 맥락에서 등장합니다.

 

대표적으로, AI 개발서적이나 GDC 발표를 통해 Halo, Half-Life, F.E.A.R 등 유명 게임들의 AI 구현 이야기가 전해졌는데, 초기에는 모두 거대한 FSM으로 시작했다가 관리 지옥에 빠졌다는 공통된 반성이 있습니다.

 

이를 해결하기 위해 Halo 2에서는 Behavior Tree(그 당시 “Decision tree”라고 불렀지만 개념은 유사)를 도입했고, F.E.A.R에서는 GOAP(Goal-Oriented Action Planning)라는 다른 접근을 취하기도 했습니다.

 

이 과정에서 FSM의 병행성 한계를 지적하며, 새로운 아키텍처들이 환영받았습니다.

 

Behavior Tree의 창시자격인 BT 개발자들이 Robotic 분야 논문을 게임에 적용하거나, 자연스러운 행동 중첩(예: 동시에 여러 감각 처리)을 위해 병행 노드를 설계한 것도 이 맥락입니다.

 

요컨대, 서구권 게임 개발사들은 2000년대 중반부터 FSM의 단점을 보완할 구조로 BT나 HFSM을 채택했고, 현재는 AAA 게임 AI의 주류가 Behavior Tree가 된 상황입니다.

 

Unity 커뮤니티에서도 영어권 개발자들이 작성한 튜토리얼과 오픈소스가 풍부합니다.

 

앞서 소개한 ScriptableObject FSM 패턴 역시 Unity 공식 Live Session을 통해 전세계에 알려졌고, 이를 기반으로 개선한 오픈소스 프로젝트들이 GitHub에 다수 존재합니다.

 

예를 들어 **Unity-FSM**, **Unity AI Framework** 등의 이름으로 상태 머신 코드와 사용법을 공개한 리포지토리들이 있고, **Playmaker** 같은 자산도 본질적으로는 시각적 FSM 도구입니다.

 

Behavior Tree에 관해서는, 유명한 오픈소스 라이브러리로 **BehaviorTree.CPP** (C++용, AI Game Dev에도 쓰임)라든가, Unity C#용으로는 **Fluid Behavior Tree**, **NPBehave**, **AI-Framework** 등이 GitHub에 공개되어 있습니다.

 

이들 라이브러리는 대부분 병행 노드(Parallel 또는 Simultaneous Task)를 지원하며, 유닛 테스트와 에디터데모를 통해 병행 상태 관리가 제대로 동작함을 보여줍니다.

 

또한 로보틱스 커뮤니티와 교류가 많아, ROS용 Behavior Tree와 게임 AI BT가 서로 영향을 주고 있습니다.

 

최근에는 Behavior Tree와 Utility AI를 결합하거나, Behavior Tree를 상태머신/블랙보드와 혼합한 하이브리드도 연구되고 있어, 병행 상태 머신 개념도 더욱 확장되고 있습니다.

 

계층형 FSM과 병행성을 동시에 추구한 사례로, **SCXML (State Chart XML)** 표준을 들 수 있습니다.

 

SCXML은 W3C 표준으로 상태차트를 XML로 기술하는 포맷인데, 병행 상태(<parallel> 태그)와 계층 상태를 모두 지원하여 복잡한 UI나 워크플로우를 기술하는데 사용됩니다.

 

게임 쪽에서는 많이 쓰이지 않지만, 비슷한 사고를 가진 프레임워크로 **Spring Statemachine**(자바 기반)이 있어서 백엔드 워크플로우나 슬라임월드 RPG AI 등에 활용된 예가 있습니다.

 

Spring Statemachine은 병렬 상태 실행을 지원해 상태 변경 처리가 빨라진다고 문서에 언급돼 있습니다.

 

이러한 산업/웹 기술에서도 병행 상태 머신 개념이 도입되는 걸 보면, 결국 병행 상태 관리는 복합 시스템 전반의 관심사라는 것을 알 수 있습니다.

 

Unity와 관련하여 영어권에서 눈에 띄는 오픈소스로는 **UnityHFSM** 라이브러리가 있습니다. 이것은 Hierarchical FSM을 효율적으로 구현한 C# 라이브러리로, 성능과 사용성을 모두 잡았다고 소개됩니다.

 

UnityHFSM은 상태가 Exit될 때까지 전이를 지연시키는 기능(needsExitTime) 등 Unity Animator와 유사한 개념도 제공하여, 게임 개발에 맞춘 계층형/병행 FSM을 코드로 쓸 수 있게 합니다.

 

이런 라이브러리를 통해 개발자는 일일이 FSM 구조를 짜지 않고도 손쉽게 병행 상태(예: 모종의 조건이 만족될 때까지 두 상태를 병렬 유지) 같은 것을 구현할 수 있습니다.

 

또한, **XState**와 같은 자바스크립트 FSM/Statechart 라이브러리가 웹 개발자 사이에 인기를 끌면서, 이 개념들이 게임 엔진 밖에서도 널리 쓰이고 있는데, XState는 React 등 UI 프레임워크와 결합되어 복잡한 UI 상태를 병렬로 관리하는데 활용됩니다.

 

XState의 개발사(Stately.ai) 문서에서는 병행 상태를 “한 부모 상태 아래 여러 지역(region)의 상태들이 동시에 활성화될 수 있는 상태”로 정의하고, 뮤직 플레이어 등의 예제를 통해 설명합니다.

 

비록 UI 예시이지만, 이러한 설명과 예제들은 게임플레이 로직에도 동일하게 적용될 수 있습니다.

 

결국 전세계적으로 병행 상태 머신 개념은 다양한 형태로 구현되고 공유되고 있으며, Unity를 사용하는 개발자들도 GitHub, 블로그, GDC 발표 등을 통해 서로의 시도를 학습하면서 발전시켜 나가고 있습니다.

 

개인적인 인사이트

여러 지역의 사례를 조사하면서 느낀 점은, **개발 규모나 문화에 따라 FSM/BT 활용 양상이 다르지만, 근본적으로 해결하고자 하는 문제는 같다**는 것입니다.

 

모두들 복잡한 상태와 동작을 어떻게 잘 관리할까 고민하고 있었고, 그 해답으로 병행 상태 머신, 계층화, 또는 전혀 다른 접근(플래너 등)을 모색했습니다.

 

한국 개발자들은 실제 적용 경험을 NDC 등을 통해 적극 공유하면서 지식을 쌓아왔고, 일본 개발자들은 자체 툴을 만들 정도로 열의를 보였으며, 영어권은 방대한 문헌과 오픈소스로 표준화된 솔루션들을 구축해놨습니다.

 

이런 자료를 접하며 제게 든 생각은, **"궁극적으로 중요한 것은 개념 그 자체보다 그것을 얼마나 쉽게 쓸 수 있게 만드느냐"** 입니다.

 

병행 상태 머신이라는 개념도, Unity Animator처럼 편리한 도구가 있으면 누구나 자연스럽게 쓰지만, 지원이 부족하면 개발자가 직접 구현해야 하므로 부담이 커집니다.

 

다행히 오늘날은 오픈소스 라이브러리나 에셋이 잘 갖춰져 있어서, 필요하면 얼마든지 가져다 쓸 수 있습니다.

 

예전에 비해 개념 구현의 진입장벽이 낮아진 만큼, 앞으로는 더 복잡한 AI나 시스템도 다양한 병행 상태 머신 기법을 통해 우아하게 관리하는 사례가 늘 것이라 기대됩니다.

 

또한 지역별로 공유되는 지식의 수준 차이는 인터넷과 번역 등의 발달로 줄어들고 있어서, 전세계 개발자들이 비슷한 문제를 두고 소통하며 같이 발전할 수 있다는 점도 고무적이었습니다.

 

마지막으로, 여러 사례를 보면서 깨달은 것은 **실무에서의 유연성**입니다.

 

이론적으로 완벽해 보이는 아키텍처라도 상황이 달라지면 다른 방법이 더 나을 수 있고, 어떤 경우에는 단순한 것이 최선일 수도 있습니다.

 

병행 상태 머신을 도입하는 것도, 그 필요성이 명확한 곳에 선별적으로 적용해야지 남용해서는 안되겠다는 생각을 했습니다.

 

사례들을 통해 얻은 이런 통찰들을 저의 앞으로의 개발에도 적용해보고자 합니다.

 

4. 결론 및 느낀점

지금까지 병행 상태 머신의 개념과 Unity 게임 개발에서의 활용 방법, 그리고 국내외 사례를 폭넓게 살펴보았습니다.

 

**병행 상태 머신**은 복잡한 시스템의 여러 상태를 동시에 관리할 수 있게 해주는 강력한 개념으로, UML의 이론적 뒷받침과 함께 실제 게임 개발에서도 점진적으로 중요성이 부각되고 있습니다.

 

Unity 엔진에서는 내장된 Animator의 병행 상태 기능, ScriptableObject를 활용한 FSM 설계, Behavior Tree 등의 다양한 기법을 통해 병행 상태 관리가 실현되고 있음을 확인했습니다.

 

각 기법마다 장단점이 있지만, 궁극적으로는 개발하려는 게임의 요구사항에 가장 잘 맞는 방식을 선택하는 것이 중요합니다.

 

예를 들어 단순한 FSM으로 시작했지만 AI가 복잡해지면 BT로 전환한다든지, 한 객체에 다수의 FSM을 붙여 관심사를 분리한다든지 하는 유연한 대처가 필요합니다.

 

이번 조사를 통해 개인적으로 얻은 가장 큰 배움은 **“복잡성을 다루는 기술로서 병행 상태 머신은 매우 유용하지만, 궁극적으로 사람(개발자)이 이해하고 다룰 수 있어야 의미가 있다”**는 점입니다.

 

좋은 아키텍처는 그것을 사용하는 사람이 쉽게 이해하고 수정할 수 있도록 도와줘야 합니다.

 

병행 상태 머신도 적절한 시각화와 구조화가 뒷받침될 때 비로소 효과적입니다.

 

다행히 Unity와 주변 생태계에는 이를 지원하는 도구와 사례가 쌓여가고 있으니, 개발자로서 이러한 자원을 적극 활용하고 기여하는 자세가 필요하겠습니다.

 

마지막으로, 오늘 정리한 내용을 제 개발 블로그 TIL(Today I Learned) 형태로 남겨둠으로써, 같은 고민을 하는 다른 분들과 지식을 공유하고 싶습니다.

 

상태 머신 설계는 게임 개발의 재미있는 부분 중 하나이고, 병행 상태까지 고려하면 처음엔 난해하지만 풀면 쾌감이 있는 퍼즐과도 같습니다.

 

앞으로 실제 프로젝트에서 이 개념을 적용해보고, 또 새로운 통찰이 생긴다면 계속해서 기록을 이어갈 생각입니다.

 

긴 글 읽어주셔서 감사드리며, 이 정리가 병행 상태 머신을 이해하고 활용하려는 분들께 유익한 참고 자료가 되길 바랍니다.