TIL(2024,08,27)상태 패턴(State Pattern)

김보근·2024년 8월 27일

Unity

목록 보기
71/113
post-thumbnail

TIL: Unity에서 상태 패턴(State Pattern) 구현하기

오늘은 Unity에서 상태 패턴(State Pattern)을 사용하여 캐릭터의 상태를 관리하는 방법을 배웠다. 상태 패턴은 게임에서 캐릭터의 다양한 상태(Idle, Run, Attack 등)를 효율적으로 관리하고, 상태 전환을 매끄럽게 처리할 수 있도록 도와주는 중요한 디자인 패턴이다. 이 패턴을 적용하여 Unity에서 캐릭터의 동작을 체계적으로 구현할 수 있었다.

상태 패턴이란?

상태 패턴은 객체의 상태에 따라 동작을 다르게 수행할 수 있게 해주는 디자인 패턴이다. 상태 패턴을 사용하면 상태별로 독립적인 클래스에서 상태 전환과 로직을 처리할 수 있어 코드의 가독성과 유지보수성이 높아진다. 이 패턴은 특히 캐릭터의 상태 관리, 예를 들어 Idle(대기), Run(달리기), Attack(공격)등등 과 같은 상황에 유용하다.

구현 코드

IState 인터페이스

모든 상태 클래스가 구현해야 하는 인터페이스이다. 각 상태 클래스는 이 인터페이스를 구현하여 상태 진입, 상태 실행, 상태 종료 시에 수행할 작업을 정의한다.

public interface IState
{
    void Enter();   // 상태에 진입할 때 호출
    void Execute(); // 상태가 활성화되어 있을 때 매 프레임 호출
    void Exit();    // 상태에서 벗어날 때 호출
}

상태 클래스 구현

각 상태에 해당하는 클래스를 정의한다. 예를 들어, Idle 상태, Run 상태, Attack 상태에 대해 아래와 같이 구현해보았다.

public class IdleState : IState
{
    private PlayerController playerController;

    public IdleState(PlayerController controller)
    {
        playerController = controller;
    }

    public void Enter()
    {
        Debug.Log("대기 상태");
        // playerController.SetAnimation("Idle");
    }

    public void Execute()
    {
        // Idle 상태에서는 입력을 감지하여 상태를 변경
        if (Input.GetKeyDown(KeyCode.W) || Input.GetKeyDown(KeyCode.A) || Input.GetKeyDown(KeyCode.S) || Input.GetKeyDown(KeyCode.D))
        {
            playerController.ChangeState(new RunState(playerController));
        }
        else if (Input.GetKeyDown(KeyCode.Space))
        {
            playerController.ChangeState(new AttackState(playerController));
        }
    }

    public void Exit()
    {
        Debug.Log("대기 상태 종료");
    }
}
public class RunState : IState
{
    private PlayerController playerController;

    public RunState(PlayerController controller)
    {
        playerController = controller;
    }

    public void Enter()
    {
        Debug.Log("달리기 상태");
        // playerController.SetAnimation("Run");
        playerController.SetSpeed(playerController.runSpeed);
    }

    public void Execute()
    {
        // 캐릭터 이동 처리
        playerController.MoveCharacter();

        // 이동 입력이 없으면 Idle 상태로 전환
        if (!Input.GetKey(KeyCode.W) && !Input.GetKey(KeyCode.A) && !Input.GetKey(KeyCode.S) && !Input.GetKey(KeyCode.D))
        {
            playerController.ChangeState(new IdleState(playerController));
        }
    }

    public void Exit()
    {
        Debug.Log("달리기 종료");
        playerController.SetSpeed(0); // 속도를 0으로 설정
    }
}
public class AttackState : IState
{
    private PlayerController playerController;

    public AttackState(PlayerController controller)
    {
        playerController = controller;
    }

    public void Enter()
    {
        Debug.Log("공격 상태");
        // playerController.SetAnimation("Attack");
    }

    public void Execute()
    {
        // 공격 실행 로직

        // 공격이 끝나면 Idle 상태로 전환
        if (!Input.GetKey(KeyCode.Space))
        {
            playerController.ChangeState(new IdleState(playerController));
        }
    }

    public void Exit()
    {
        Debug.Log("공격 상태 종료");
    }
}

PlayerController 클래스

PlayerController 클래스는 현재 캐릭터의 상태를 관리하고, 상태 전환을 처리한다. 이 클래스는 게임 루프(Update 메서드)에서 현재 상태를 실행하고, 필요에 따라 상태를 전환한다.

public class PlayerController : MonoBehaviour
{
    private StateContext stateContext;
    public float runSpeed;

    private void Start()
    {
        stateContext = new StateContext();
        stateContext.SetState(new IdleState(this));  // 초기 상태를 Idle로 설정
    }

    private void Update()
    {
        stateContext.Update();
    }

    // 상태 전환을 위한 메서드
    public void ChangeState(IState newState)
    {
        stateContext.SetState(newState);
    }

    // 애니메이션 설정 (현재 주석 처리)
    // public void SetAnimation(string animationName)
    // {
    //     GetComponent<Animator>().Play(animationName);
    // }

    // 속도 설정
    public void SetSpeed(float speed)
    {
        // 캐릭터의 이동 속도 설정 로직
    }

    // 캐릭터 이동 처리
    public void MoveCharacter()
    {
        // 이동 입력에 따라 캐릭터를 움직이는 로직
    }
}

StateContext 클래스

StateContext 클래스는 현재 상태를 관리하고, 상태 전환 및 상태 업데이트를 처리한다. 이 클래스는 상태 패턴의 핵심 역할을 한다.

public class StateContext
{
    private IState currentState;

    public void SetState(IState state)
    {
        if (currentState != null)
        {
            currentState.Exit(); // 현재 상태에서 벗어날 때 Exit 메서드 호출
        }

        currentState = state;
        currentState.Enter(); // 새로운 상태로 전환할 때 Enter 메서드 호출
    }

    public void Update()
    {
        if (currentState != null)
        {
            currentState.Execute(); // 현재 상태가 실행 중일 때 Execute 메서드 호출
        }
    }
}

요약

오늘은 Unity에서 상태 패턴을 사용해 캐릭터의 상태 전환을 구현하는 방법을 배웠다. 상태 패턴은 각 상태를 독립적인 클래스로 분리하여 관리하고, 상태 전환 시 일관된 방법으로 상태를 변경할 수 있도록 도와준다. 이로 인해 코드의 가독성과 유지보수성이 크게 향상되었다.

애니메이션 부분은 주석 처리해 두었지만, 실제로는 상태 전환 시 Enter, Exit 메서드에서 적절한 애니메이션 전환을 처리하게 된다. 앞으로 이 패턴을 활용해 다양한 캐릭터 동작을 더욱 체계적으로 구현할 수 있을 것이다.

profile
게임개발자꿈나무

0개의 댓글