[Unity] 뱀서라이크 클론코딩 기록 #3 (Spriter, Animator)

earlook99·2023년 11월 12일

Spriter, Animator를 이용하여 2D 셀 애니메이션을 제작해보자.


1. Player Object에 분할된 여러 장의 스프라이트를 Drag&Drop하여 Animator 컴포넌트 생성

2. Animation 경로에 자동으로 생성된 Animator Controller를 더블클릭하여 Animator 창 열기

3. Animator 창에서의 작업

4. Player 스크립트에 해당 작업을 제어할 수 있는 코드 추가


Animator 창 (상태 머신)

Entry : 시작
Any State : 모든 상태
Exit : 종료

우클릭 -> Make Transition으로 Transition(화살표) 생성

Parameters에서 파라미터 생성 가능 (Float, Int, Bool, Trigger)

Transition을 클릭하여 Inspector 창에서의 다양한 제어

Settings에서

  • Has Exit Time : 애니메이션 상태가 다른 상태로 전환되는 시점을 정의 (이 셀 애니메이션 프로젝트에서는 사용하지 않음)
  • Transition Duration : 애니메이션 상태가 다른 상태로 전환되는 데 걸리는 시간을 정의 (0.01로 설정, 일단은)

Conditions에서

  • Parameter 값을 기준으로 Transition 수행을 제어할 수 있다
    ex) SpeedGreater than 0.01

스크립트에 Animator, Spriter 제어 코드 추가

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

public class Player : MonoBehaviour
{
    public Vector2 inputVec;
    public float speed;

    Rigidbody2D rigid;
    SpriteRenderer spriter;
    Animator anim;

    void Awake()
    {
        rigid = GetComponent<Rigidbody2D>();
        spriter = GetComponent<SpriteRenderer>();
        anim = GetComponent<Animator>();
    }

    void FixedUpdate()
    {
        Vector2 nextVec = inputVec * speed * Time.fixedDeltaTime;
        rigid.MovePosition(rigid.position + nextVec);
        
    }

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

    void LateUpdate()
    {
        anim.SetFloat("Speed", inputVec.magnitude);

        if (inputVec.x != 0) {
            spriter.flipX = inputVec.x < 0;
        }
    }
}


SpriteRenderer spriter;
Animator anim;

SpriteRendererAnimator 컴포넌트를 참조할 수 있는 변수 spriteranim을 선언한다.


LateUpdate 함수

Update 계열 함수(프레임 단위로 호출되는)이며, 다른 모든 Update 계열 함수가 호출된 후 마지막으로 호출된다.

void LateUpdate()
{
    anim.SetFloat("Speed", inputVec.magnitude);
    if (inputVec.x != 0) {
        spriter.flipX = inputVec.x < 0;
    }
}
  • anim 변수를 통해 Animator에 접근하여, Speed 파라미터에 inputVec 벡터의 크기(길이)를 대입한다. 이를 통해 방향키 입력으로 Stand 애니메이션과 Run 애니메이션 간의 Transition을 제어할 수 있게 되었다.
  • 방향키 입력이 존재할시 spriter의 filp 파라미터(X방향)에
    inputVec.x < 0 이면 (왼쪽 입력이면), True 대입 - 체크
    inputVec.x > 0 이면 (오른쪽 입력이면), False 대입 - 체크해제 (기본 애니메이션이 오른쪽을 보고 있다)
    if문을 이중으로 쓰지 않고 비교연산자를 통해 효율적인 제어가 가능하다.

왜 애니메이션은 LateUpdate?

  • LateUpdate는 모든 Update 함수가 호출된 후, 즉 모든 물리 계산이 완료된 후에 실행된다.
  • 애니메이션과 카메라 추적과 같은 작업은 게임 오브젝트의 최종 위치가 결정된 후에 실행되어야 한다. 이를 통해 프레임마다 부드럽고 일관된 애니메이션과 카메라 움직임이 보장된다.
  • 이 프로젝트의 코드로 예를 들면, 캐릭터의 이동이 FixedUpdate에서 처리된 후, LateUpdate에서 해당 이동에 맞는 애니메이션 상태가 조정된다. 이렇게 함으로써, 애니메이션이 이동과 동기화되어 보다 자연스럽게 보일 수 있다.

Animator Override Controller

기존 Animator Controller를 상속하여 사용할 수 있는 Animator Controller이다.

생성 후 Inspector에서 Controller 파라미터에 상속받을 기존 Animator Controller를 할당한다.

그 밑 Override 칸에 각각의 새로운 애니메이션 (필요하다면) 또한 할당한다.


#코드 요약

MonoBehaviour 클래스를 상속받는 Player 클래스의 스크립트이다.

이동을 위한 방향키 입력값을 벡터로 받는 inputVec 변수, 이동 속도를 정의하는 speed 변수, Rigidbody2D 컴포넌트를 참조할 수 있는 rigid 변수를 각각 정의한다.

Awake 함수에서는 초기화를 수행한다. Player 오브젝트에 부착된 Rigidbody2D 컴포넌트를 rigid 변수가 참조하도록 한다.

OnMove 함수에서는 방향키 입력을 제어한다. value 매개변수로 입력값을 받아온 후, inputVec 변수에 벡터 형태로 변환하여 대입한다.

FixedUpdate 함수에서는 플레이어의 이동을 제어한다. 우선 Player가 현재 위치로부터 이동해야 할 벡터값을 계산한다. 이는 inputVec값에 speed 변수의 값과 다음 FixedUpdate 호출까지의 시간 간격 값을 전부 곱한 것과 같다. 그 다음 rigid(= Player에 부착된 Rigidbody2D 컴포넌트)가 rigid의 현재 위치 + 앞에서 계산된 벡터값의 위치에 놓이도록 한다. 이를 일정한 시간 간격으로 수행한다.

LateUpdate 함수에서는 플레이어의 애니메이션을 제어한다. anim 변수를 통해 Animator에 접근 후 Speed 파라미터에 inputVec의 크기를 대입하여 애니메이션 상태간의 Transition을 조정한다. 또한 방향키 입력값이 존재할 때, inputVec 값의 부호에 따라 spriter 변수를 통해 SpriteRenderer에 접근하여 flip 체크박스의 상태를 제어한다.


출처 :
링크텍스트

profile
hongikuniversity

0개의 댓글