유니티

상태(State) 패턴 with Unity

코다람쥐 2022. 2. 4. 22:03

1. 상태 패턴

상태 패턴은 객체에 상태를 정해서 상태에 맞는 로직을 수행하는 디자인 패턴이다.

 

사용하는 이유

if와 else로만 구현을 하게되면 스파게티 코드가 될 수 있기 때문에 객체의 상태로 분리시켜서 로직을 수행하면 이러한 문제를 해결할 수 있다.

 

enum과 swtich를 활용한 상태 패턴

우선 enum을 통해서 상태를 열거한다.

    public enum PlayerState
    {
        Die,
        Moving,
        Idle,
    }

 

업데이트문에서 switch문을 통해서 상태에따라 실행될 함수들을 집어넣는다.

    PlayerState _state = PlayerState.Idle;
    void Update()
    {
        switch(_state)
        {
            case PlayerState.Die:
                UpdateDie();
                break;
            case PlayerState.Moving:
                UpdateMoving();
                break;
            case PlayerState.Idle:
                UpdateIdle();
                break;
        } 
    }

 

이런식으로 함수들을 정의하여 이제 상태가 변화하면 그에 맞는 로직을 처리하게끔 구현이 된다.

    void UpdateMoving()
    {
        Vector3 dir = _destPos - transform.position; // 방향값 가져오기
        if (dir.magnitude < 0.001f) // 도착완료하면 false로 설정
        {
            //_moveToDest = false;
            _state = PlayerState.Idle;
        }
        else
        {
            // 이동한 좌표에서 부들거리는 현상 제거
            float moveDist = Mathf.Clamp(_speed * Time.deltaTime, 0, dir.magnitude);

            // 목적지 좌표에 도착할 때 까지 계속 이동시킴
            transform.position += dir.normalized * moveDist;

            // 부드럽게 회전
            transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(dir), 10 * Time.deltaTime);
        }
        // 애니메이션
        wait_run_ratio = Mathf.Lerp(wait_run_ratio, 1, 10.0f * Time.deltaTime);
        Animator anim = GetComponent<Animator>();
        anim.SetFloat("wait_run_ratio", wait_run_ratio);
        anim.Play("WAIT_RUN");
    }
    void UpdateIdle()
    {
        //애니메이션
        wait_run_ratio = Mathf.Lerp(wait_run_ratio, 0, 10.0f * Time.deltaTime);
        Animator anim = GetComponent<Animator>();
        anim.SetFloat("wait_run_ratio", wait_run_ratio);
        anim.Play("WAIT_RUN");
    }

위의 코드는 Idle상태가 기본이었다가 이동명령이 발생하면 Moving상태로 변화하고 이동이 끝나면 다시 Idle상태로 되돌아가는 로직이다.

 

만약 새로운 기능을 추가하고 싶으면 enum과 switch문에만 상태를 추가하고 로직은 따로 구현만 하면 된다.