State 패턴

JJW·2024년 12월 4일

Unity

목록 보기
10/34

오늘은 State 패턴에 대해 알아보는 시간을 가지겠습니다.


State 패턴이란 ?

  • 객체의 상태에 따라 그 객체의 행동이 달라지도록 설계하는 디자인 패턴입니다.
  • 주로 상태를 변경해야 할 필요가 있을 때 객체의 행동을 수정하지 않고, 상태별로 객체를 나누어 코드의 유연성과 확장성을 높이는 데 도움을 줍니다

State 특징

  • 객체의 상태를 캡슐화
    • 상태를 나타내는 클래스들이 각각의 상태별 행동을 구현하며, 이러한 클래스를 통해 상태를 캡슐화합니다.
  • 상태 전환을 명확하게 정의
    • 상태 객체들이 현재 상태에 따라 다른 상태로 전환할 수 있도록 도와줍니다. 상태 전환은 Context 객체나 상태 클래스에서 관리할 수 있습니다.
  • 행동의 다형성 사용
    • 각 상태 클래스가 공통 인터페이스 또는 추상 클래스를 구현하여 다형성을 제공합니다. 이를 통해 현재 상태에 따라 다른 행동이 자연스럽게 호출됩니다.
  • 상태 독립성
    • 각 상태는 다른 상태로부터 독립적이며, 개별 상태를 수정하더라도 다른 상태에 영향을 미치지 않습니다.

주요 구성 요소

1. Context

public class StateMachine
{
    private IState currentState;

    // 상태 변경 메서드
    public void SetState(IState newState)
    {
        if (currentState != null)
        {
            currentState.Exit(); // 현재 상태에서 나가기
        }

        currentState = newState;

        if (currentState != null)
        {
            currentState.Enter(); // 새 상태로 들어가기
        }
    }

    // 현재 상태 유지 및 업데이트
    public void Update()
    {
        if (currentState != null)
        {
            currentState.Execute(); // 현재 상태 실행
        }
    }
}
  • 현재 상태 객체를 유지합니다.
  • 상태 전환을 요청할 때 상태 객체를 교체합니다.
  • 행동의 실행을 각 상태 객체에 위임합니다.

2. State

public interface IState
{
    void Enter();   // 상태로 진입할 때 호출되는 메서드
    void Execute(); // 상태가 유지되는 동안 호출되는 메서드
    void Exit();    // 상태에서 벗어날 때 호출되는 메서드
}
  • 공통된 메서드를 정의하여, 상태별로 일관된 행동을 보장합니다.
  • 각 상태가 수행해야 할 메서드들을 명확하게 정의하여 상태별 구현을 쉽게 만듭니다.

3. ConcreteState

public class IdleState : IState
{
    public void Enter()
    {
        Debug.Log("Entering Idle State");
    }

    public void Execute()
    {
        Debug.Log("Executing Idle Behavior: Standing still");
    }

    public void Exit()
    {
        Debug.Log("Exiting Idle State");
    }
}

public class AttackState : IState
{
    public void Enter()
    {
        Debug.Log("Entering Attack State");
    }

    public void Execute()
    {
        Debug.Log("Executing Attack Behavior: Attacking the target");
    }

    public void Exit()
    {
        Debug.Log("Exiting Attack State");
    }
}
  • 상태 전환 시 수행해야 할 초기화 코드나 종료 코드를 Enter와 Exit 메서드에 정의합니다.
  • 해당 상태에서 지속적으로 수행할 행동을 Execute 메서드에 정의합니다.
  • 상태 전환 조건이 충족되면, Context의 상태를 변경할 수 있습니다.

4. GameManager

public class GameManager : MonoBehaviour
{
    private StateMachine stateMachine; // 상태 머신
    private IdleState idleState;       // Idle 상태
    private AttackState attackState;   // Attack 상태

    void Start()
    {
        // 상태 머신 및 상태 객체 초기화
        stateMachine = new StateMachine();
        idleState = new IdleState();
        attackState = new AttackState();

        stateMachine.SetState(idleState);
    }

    void Update()
    {
        stateMachine.Update();

        // 상태 전환 조건
        if (Input.GetKeyDown(KeyCode.A))
        {
            stateMachine.SetState(attackState); // 공격 상태로 전환
        }
        else if (Input.GetKeyDown(KeyCode.I))
        {
            stateMachine.SetState(idleState); // Idle 상태로 전환
        }
    }
}
  • 실제 사용하는 경우입니다. 객체 초기화가 이루어 진 뒤 Input.GetKey()로 상태 변화를 체크합니다.

State 패턴의 흐름

  • 초기 상태 설정
  • 상태 유지
  • 상태 전환
  • 이 흐름이며 위 코드로 설명해보자면
  • SetState() : 초기 상태 설정
  • Update() : 상태 유지
  • Input.GetKeyDown() : 상태 전환

State 패턴의 장단점

  • 장점
  • 유지보수 용이성
  • 코드의 가독성 증가
  • 중복 제거
  • 명확한 상태 전환 관리
  • 단점
  • 클래스 수 증가로 인한 복잡성 증가
  • 의사결정의 분산

State 패턴의 쓰임새

  • 상태가 변하는 "대기","이동","공격"... 등등 상황인 NPC AI, 플레이어 상태 관리, 애니메이션 트리거 등등의 사용됩니다.

테스트

  • 초기 상태인 Idle의 값이 계속 나오다 Input.Getkey()로 상태를 변경하니 상태 값이 변경됩니다.

느낀 점

구현 중 가장 큰 장점은 상태 전환 로직의 명확성이었습니다. 이전에는 조건문을 사용하거나 엉성하게 구현하였는데 공부하면서 구현해보니 각 상태가 무엇을 하는지 명확하게 알 수 있어 편리하였습니다..NPC AI 설계의 여러 패턴들과 조합하면 개인적으로 만족하는 AI 설계가 나오지 않을까 싶습니다..

  • 제가 조사한 내용이 맞지 않거나 잘못 된 경우에 댓글로 잘못된 점 지적해주시면 감사합니다 ! (´._.`)
profile
Unity 게임 개발자를 준비하는 취업준비생입니다..

0개의 댓글