Chapter 6-3. 애니메이션 : State 패턴

Date:     Updated:

카테고리:

태그:

인프런에 있는 Rookiss님의 [C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part3: 유니티 엔진 강의를 듣고 정리한 필기입니다. 😀
🌜 강의 들으러 가기 Click

Chapter 6. 애니메이터

🚖 State 디자인 패턴

bool isFalling;
bool isJumping;
bool isSkillCasting;
bool isSkillChanneling;

if(isJumping)
{

}
else
{
    if(isSkillChanneling && isFalling)
    {

    }
    else
    {
        if(isSkillCasting)
        {

        }
    }
}

이런식으로 bool타입의 상태 flag 변수를 여러개 사용하면 너무 복잡하다. if - else문이 너무 많아진다. 상태 flag 변수가 적은 갯수라면 괜찮지만 규모가 큰 게임일 수록 많이 필요하기 때문에 적합하지 않다.

해결 방법 👉 State 패턴 사용하기!


using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    float wait_run_ratio = 0;

    [SerializeField]
    float _speed = 10.0f;

    Vector3 _destPos;  // 목적지

    void Start()
    {
        Managers.Input.MouseAction -= OnMouseClicked;
        Managers.Input.MouseAction += OnMouseClicked;
    }

    public enum PlayerState
    {
        Die,
        Moving,
        Idle,
    }

    PlayerState _state = PlayerState.Idle;

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

    void UpdateDie()
    {
        // 아무것도 못함
    }

    void UpdateMoving()
    {
        Vector3 dir = _destPos - transform.position;
        if (dir.magnitude < 0.0001f)  // 도착함
        {
            _state = PlayerState.Idle;
        }
        else   // 도착 X 
        {
            float moveDist = Mathf.Clamp(_speed * Time.deltaTime, 0, dir.magnitude);
            transform.position = transform.position + dir.normalized * moveDist;

            transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(dir), 10 * Time.deltaTime);
            transform.LookAt(_destPos);
        }

        // 애니메이션
        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");
    }

    void OnMouseClicked(Define.MouseEvent evt)
    {
        if (_state == PlayerState.Die)
            return;

        if (evt != Define.MouseEvent.Click)
            return;

        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); 
        Debug.DrawRay(Camera.main.transform.position, ray.direction * 100.0f, Color.red, 1.0f);

        RaycastHit hit;
        if (Physics.Raycast(ray, out hit, 100.0f, LayerMask.GetMask("Wall")))
        {
            _destPos = hit.point;
            _state = PlayerState.Moving;
        }
    }
}

if (_state == PlayerState.Die)

//...

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

enum으로 상태들을 정의하고, if-else문 혹은 switch문 사용하기!

  • 대신 bool 상태 플래그 변수와는 다르게 동시에 두가지 상태를 가질 순 없음. 👉 이와 같은 특성 때문에 여러 동작이 꼬일 일이 없음. 동작 별로 분리해서 만들 수 있다는 장점.
    isJumping && isAttacking  // 👉 가능
    
    _state == PlayerState.Jump && _state == PlayerState.Attack  // 👉 불가능
    


🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우 
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄

맨 위로 이동하기

Unity Lesson 2 카테고리 내 다른 글 보러가기

댓글 남기기