게임 리팩토링 - 플레이어 이동, 애니메이션

찡완이·2023년 8월 15일
0

서론

  • 고1때 만들었던 게임 리팩토링입니다.
  • 코드가 너무 난해해서 사실상 다시 만드는 수준으로 하고 있습니다.
  • 스프라이트, 음악 파일등은 전 게임에서 그대로 따오고 코드만 갈아엎는 방식으로 진행하고 있습니다.

-> 스크립트도 복잡하고 스프라이트도 정리가 되어 있지 않은 모습

1. 플레이어 이동

1.1. 기존 이동 방식

  • 대각선 이동이 제한된 수직,수평 이동 방식
  • InputManager를 활용(ex : Input.GetAxis())
  • 조작감 향상을 위해 키 2개를 동시에 누르는 경우, 나중에 누른 키를 기준으로 이동할 수 있도록 설계했으나, 실제로는 수직이동에서만 적용되고, 수평이동에서는 적용되지 않았음.

기존 코드

void Move() {
        Ar_x = Input.GetAxisRaw("Horizontal"); 

        bool isMovingHorizontal = Mathf.Abs(Ar_x) > 0.5f;

        Ar_y = Input.GetAxisRaw("Vertical"); 
        bool isMovingVertical = Mathf.Abs(Ar_y) > 0.5f;

        bool wasMovingVertical = true;
        if (isMovingHorizontal && isMovingVertical) { //두개의 버튼이 눌린 경우

            if (wasMovingVertical) {
                rigid.velocity = new Vector2(Ar_x * speed, 0); //수평이동
                lastMove = new Vector2(Ar_x, 0f);
                Ar_y = 0; //
            } else {
                rigid.velocity = new Vector2(0f, Ar_y * speed); // 수직이동
                Ar_x = 0; //
            }

        } else if (isMovingHorizontal) {
            rigid.velocity = new Vector2(Ar_x * speed, 0f);
            wasMovingVertical = false;
            lastMove = new Vector2(0f, Ar_x);
            Ar_y = 0; //
        } else if (isMovingVertical) {
            rigid.velocity = new Vector2(0, Ar_y * speed);
            wasMovingVertical = true;
            lastMove = new Vector2(0f, Ar_y);
            Ar_x = 0; //
        } else {
            rigid.velocity = Vector2.zero;
        }
    }

1.2. 수정 방향

  • InputSystem을 활용 (ex : OnMove())
  • 조작감 향상을 위해 키 2개를 누르는 경우엔 나중에 누른 키를 기준으로 이동하는 시스템 구성

1.3. 해결 과정

1.3.1. InputManager 도입

1.3.2. 조작감 향상을 위한 코드 설계

변경 코드

public void OnMove(InputValue value)
    {
        inputVec = value.Get<Vector2>();

        /*입력받은 벡터의 x,y값 크기를 1로 보정*/
        if (inputVec.x != 0)
            inputVec.x = inputVec.x > 0 ? 1 : -1;
        if (inputVec.y != 0)
            inputVec.y = inputVec.y > 0 ? 1 : -1;

        if (Mathf.Abs(inputVec.x + inputVec.y) == 1) // 키 하나만 입력
        {
            dir = inputVec;
            preVec = dir;
        }
        else if (inputVec.x == 0 && inputVec.y == 0) // 입력이 없으면
            dir = Vector2.zero; 
        else if (preVec != inputVec) // 2개의 키를 입력할 때
        {
            preVec = inputVec - preVec;
            dir = preVec;
        }
    }

    private void Update()
    {
        rigid.MovePosition(rigid.position + dir * speed * Time.deltaTime);
        rigid.velocity = Vector2.zero;
    }

2. 플레이어 애니메이션

2.1. 기존 애니메이션

  • 애니메이터의 구성이 복잡해서 한번에 보기 힘들었음.
  • 애니메이터의 구조적 문제로 인해 왼쪽에서 오른쪽으로 이동할 때 필연적으로 디폴트값, 정면을 바라보는 애니메이션을 거쳐가야 했기에 부자연스러운 부분 존재.
  • 애니메이션 전환에 사용되는 Parameter가 직관적이지 않음.
  • Parameter가 직관적이지 않으므로 애니메이션 구현 코드도 복잡함.
if (Ar_x == 0 && Ar_y == 1) {
            anim.SetInteger("Direction", 1); 
            anim.SetBool("Move", true);
            direction = 3;
        } else if (Ar_x == 1 && Ar_y == 0) {
            anim.SetInteger("Direction", 2); 
            anim.SetBool("Move", true);
            direction = 2;
        } else if (Ar_x == 0 && Ar_y == -1) {
            anim.SetInteger("Direction", 3); 
            anim.SetBool("Move", true);
            direction = 1;
        } else if (Ar_x == -1 && Ar_y == 0) {
            anim.SetInteger("Direction", 4); 
            anim.SetBool("Move", true);
            direction = 0;
        }

        if ((Input.GetKeyDown(KeyCode.R) || b_fire) && !fired && firework_Count > 0) // 폭죽 발사 코드
        {
            Instantiate(firework, transform.position, Quaternion.Euler(0, 0, 90 * direction));
            fired = true;
            firework_Count -= 1;
            b_fire = false;
        }

        if (Ar_x == 0 && Ar_y == 0)
        {
            anim.SetBool("Move", false);
            anim.SetInteger("Direction", 0);
            isMove = false;
        }
        else
            isMove = true;

2.2. 수정 방향

  • 플레이어의 이동방향(DirX,DirY)과 플레이어의 이동 여부(IsMove)를 Parameter로 사용.
  • 블렌더 트리를 활용하여 애니메이터 구조 단순화
    -> https://unitybeginner.tistory.com/74
  • 애니메이션 구현 부분을 함수로 만들어 따로 분류

2.3. 해결 과정

  • Parameter를 DirX, DirY, IsMove로 직관화
  • 블렌더 트리를 활용해서 애니메이션 정리

애니메이터 구조

블렌더 트리 내부

  • InputSystem의 값을 기반으로 코드 설계
private void Animate() // animDir : 플레이어가 바라보는 방향 벡터
    {
        if (dir.x != 0 || dir.y != 0) // 플레이어가 움직이는 경우
        {
            animDir = dir; 
            anim.SetBool("IsMove", true);
        }
        else
            anim.SetBool("IsMove", false);

        anim.SetFloat("DirX", animDir.x);
        anim.SetFloat("DirY", animDir.y);
    }
profile
코딩공부합니다

0개의 댓글