본문 바로가기
개발/게임 디자인 패턴

게임 디자인 패턴 6. 상태 패턴 (State Pattern)

by 석시 2023. 10. 30.



상태 패턴이다.

오히려 고전적인 구현에 더 많이 쓰이는 듯하다.

회로라던지 통신의 로우 레이어라던지.

상태 패턴도 요즘은 좀 남발되는 경우가 많은 것 같다.

AI가 대두되고, 이것이 게임에 적용되기 시작하면서 더더욱 그런 것 같다.

유한 상태 기계 (FSM, Finite State Machine)

유한 상태 기계상태와 상태 간의 전환을 기반으로 동작하는 동작 기반 시스템이다.

이렇게만 이야기 하면 감이 잘 오지 않는데, 이런 상황을 구해야 한다고 해보자.

청기백기 게임인데, 아래-중간-위가 있다고 해보면 다음 그림의 느낌이 될 것이다.

이 때, 상태 패턴 없이 구현을 해본다 치면?

switch (명령) {
    case (청기올려):
        if (청기 == 아래) 청기 = 중간;
        else if (청기 == 중간) 청기 = 위;
        break;
    case (청기내려):
        if (청기 == 중간) 청기 = 아래;
        else if (청기 == 위) 청기 = 중간;
        break;
    case (백기올려):
        if (백기 == 아래) 백기 = 중간;
        else if (백기 == 중간) 백기 = 위;
        break;
    case (백기내려):
        if (백기 == 중간) 백기 = 아래;
        else if (백기 == 위) 백기 = 중간;
        break;
// ...
}

벌써부터 마음에 안들지 않은가?

왜냐면, 사실 이걸 그림으로 그리면 그냥 이렇게 만들 수 있지 않은가?

그림이 다소 번잡스럽지만, 이해 바란다.

오히려 이렇게 설계하는 것이 더 직관적이지 않은가?

예상 했겠지만 위의 그림으로 나타낸 것이 바로 유한상태머신(FSM)이다.

FSM의 구성 요소는 보통 다음과 같이 구성된다.

  • 상태 (State): 시스템이 취할 수 있는 다양한 상태를 나타냄
  • 전환 조건 (Transition Condition): 상태 간 전환을 결정하는 조건
  • 동작 (Action): 상태에 따라 수행되는 동작 또는 로직

상태 패턴의 구현

보통은 인터페이스를 이용하여 구현한다.

public interface IState
{
    public void Enter();
    public void Exit();
    public void HandleInput();
    public void Update();
    public void PhysicsUpdate();
}

public abstract class StateMachine
{
    protected IState currentState;

    public void ChangeState(IState newState)
    {
        currentState?.Exit();

        currentState = newState;

        currentState?.Enter();
    }

    public void HandleInput()
    {
        currentState?.HandleInput();
    }

    public void Update()
    {
        currentState?.Update();
    }

    public void PhysicsUpdate()
    {
        currentState?.PhysicsUpdate();
    }
}

위의 기본적인 형태를 바탕으로 이를 상속 받아 다양한 상태를 만든다.

이전 게시글에 FSM을 이용하여 플레이어 이동을 구현하는 글이 있으니 그것을 링크하겠다.

Unity3D FSM으로 플레이어 캐릭터 조작 구현하기 (1)
프로젝트 세팅Input System으로 기본적인 이동 구현하기Input Actions와 오브젝트 연결하기플레이어에 애니메이션을 받도록 하는 스크립트 작성FSM 구성하기플레이어에 대한 상태 정보 구현하기 플레이어 이동 구현 방식에는 여러 가지가 있지만, 구현해야 하는 이동 상황이 많아지면 주로 사용하는 것이 바로 FSM(Finite State Machine)이다. FSM은 상태 패턴을 구현하는 방법 중 하나로 자세한 내용은 나중에 게시글로 따로 다루도록 하겠다. 이번 글에서는 FSM을 이용하여 플레이어 이동 구현하는 방식을 정리해보고자 한다. 프로젝트 세팅 사용된 애셋은 다음과 같다.ProjectAssets.unitypackage 프로젝트 패키지는 Input System을 사용할 것이기 때문에 Packag..
https://seoksii.tistory.com/56

여기서 만약 추가로 몇 가지의 상태를 더 추가하고 싶다면 기존 상태의 코드 변경 없이 추가해줄 수 있는 것이다.

우리는 이미 상태 패턴을 알고 있다

사실 지금까지 열심히 상태 패턴의 예시를 구현해봤지만, 사실 유니티 내 기능 중에 이미 상태 패턴으로 구현된 것이 있다.

바로 애니메이터 (Animator) 이다.

해당 애니메이터가 바로 상태 패턴으로 구현된 것이다!

상태 패턴의 형태

기본적으로 현재 상태 (State) 에 따른 동작 (Action) 과 상태 간을 넘나들기 위한 조건으로 이루어져 있다고 언급했다.

구조 자체가 제한되어 있기 때문에 코드는 매우 깔끔하지만, 새로 무언가를 추가하려고 해도 상태형으로만 추가해줄 수가 있는 것이다.

책에서는 FSM을 좀더 광범위하게 적용할 수 있게 하기 위해 다음과 같은 형태를 소개하고 있다.

  • 병행 상태 기계 : 한 클래스가 하나의 상태를 참조하는 것이 아닌 여러 개를 참조하는 것이다. 위의 청기 백기에서 청기, 백기 상태를 각각 두는 것이라고 생각하면 좋다.
  • 계층형 상태 기계 : 어떤 상태는 상위 상태 (Superstate) 이고 그 상위 상태에 속하는 하위 상태 (Substate)를 가질 수 있다. 위에서 링크한 FSM으로 플레이어 이동을 구현할 때 GroundState / AirState상위 상태를 나누고, GroundStateIDLE, MOVE와 같이 하위 상태를 나누는 것이 그 예이다.
  • 푸시다운 오토마타 : 진입하는 State를 전부 스택에 저장하여 스택의 Top을 현재 상태로 삼는 오토마타이다. 이렇게 하면 이전의 상태를 저장하고, 그 이전의 상태로 돌아가는 짓이 가능해진다.

언제 사용하는가?

FSM을 보통 언제 사용하는가?

보통은 위의 예시처럼 다음 동작을 하기 위해 오브젝트의 “현재 상태”가 필요한 상황일 때 쓰면 모델링이 매우 편해진다.

책에서는 다음과 같이 정리하고 있다.

  • 내부 상태에 따라 객체 동작이 바뀔 때
  • 이런 상태가 그다지 많지 않은 선택지로 분명하게 구분될 수 있을 때
  • 객체가 입력이나 이벤트에 따라 반응할 때

입력 처리나 메뉴 화면 전환, 문자 해석, 네트워크 프로토콜, 비동기 동작 등에 제일 많이 사용된다.

AI에서는 요즘 생각보다 FSM을 광범위하게 사용하지는 않는다.

시작부분에 언급했듯 요즘 게임의 AI는 행동 트리 (Behaviour Tree)계획 시스템 (Planning System) 을 더 많이 쓴다고 한다.


Uploaded by N2T