Unity 입문 TopDown Shooting - 애니메이션 컨트롤

Amberjack·2024년 1월 19일
0

Unity

목록 보기
15/44

📺 Animation & Animator

▪️ Animation:

  • Animation 컴포넌트는 게임 오브젝트에 애니메이션을 추가하는 데 사용된다.
  • 이 컴포넌트는 애니메이션 클립을 재생할 수 있다.
  • Animation 컴포넌트는 간단한 애니메이션에 적합하며, 스크립트를 통해 직접 제어할 수 있다.
  • 애니메이션 클립은 Unity의 Animation window를 통해 생성하거나 편집할 수 있다.
  • Animation 컴포넌트를 사용하여 오브젝트의 크기를 변경하거나 색상을 변환하는 등의 간단한 애니메이션을 생성할 수 있다.

▪️ Animator:

  • Animator 컴포넌트는 애니메이션의 상태를 제어하고 전환을 관리하는 데 사용된다.
  • Animator 컴포넌트는 Animation Controller를 사용하여 애니메이션의 복잡한 상태 기계를 구현할 수 있다.
  • Animator 컴포넌트는 여러 애니메이션 클립을 조절하고, 애니메이션 간의 전환을 제어하고, 복잡한 애니메이션 시퀀스를 구현하는 데 적합하다.
    ex) 캐릭터의 걷기, 뛰기, 점프 등의 애니메이션을 관리하는 데 사용될 수 있다.
  • Animator 컴포넌트는 Mecanim 애니메이션 시스템의 일부로서, 애니메이션 블렌딩, 트리, 상태 머신 등의 기능을 제공한다.

이 두 컴포넌트는 서로 다른 목적과 사용 케이스에 따라 애니메이션을 제어하는 데 사용한다. Animation은 더 간단한 애니메이션에 사용되며, Animator는 더 복잡한 애니메이션 시퀀스와 상태 관리에 사용된다.

📚 StringToHash

문자열을 해시 값으로 변환하며, 이로써 성능을 개선하고 코드의 가독성을 유지할 수 있다.

  • 문자열 비교는 상대적으로 연산 비용이 큰 작업이기 때문에 "StringToHash"는 문자열을 고유한 정수 값인 해시 값으로 변환하여 이 연산 비용을 크게 줄일 수 있다.
  • 해시 값은 고유하기 때문에 다른 문자열이 동일한 해시 값을 갖는 확률이 매우 낮다. 이를 활용해 문자열을 해시로 변환하면 효율적으로 문자열을 비교할 수 있다.
  • 애니메이션 파라미터를 지정할 때 문자열 대신 해시 값을 사용하면 CPU 시간을 절약하고 애니메이션 성능을 향상시킬 수 있다.
  • 그러나 주의할 점은 동일한 문자열은 항상 동일한 해시 값을 반환하지만, 반대로 동일한 해시 값이 항상 동일한 문자열을 반환하지는 않기 때문에, 이 점으로 인해 해시 충돌이 발생할 수 있다.
  • 또한 "StringToHash" 함수는 문자열을 해시 값으로 변환할 때 일방향으로 작동하기 때문에, 해시 값을 다시 원래의 문자열로 변환하는 것은 불가능하다.

⌨️ TopDownAnimations.cs

Controller 폴더 밑에 TopDownAnimations.cs를 생성한다.

public class TopDownAnimations : MonoBehaviour
{
    protected Animator animator;
    protected TopDownCharacterController controller;

    protected virtual void Awake()
    {
        animator = GetComponentInChildren<Animator>();
        controller = GetComponent<TopDownCharacterController>();
    }
}

⌨️ TopDownAnimationController.cs

Controller 폴더 밑에 TopDownAnimationController.cs 를 생성한다.

public class TopDownAnimationController : TopDownAnimations
{
    // StringToHash : 특정 문자열을 해시값으로 변경하여 해시값을 통해 비교함. -> 문자열 비교보다 훨씬 빠르다!
    private static readonly int IsWalking = Animator.StringToHash("IsWalking");
    private static readonly int Attack = Animator.StringToHash("Attack");
    private static readonly int IsHit = Animator.StringToHash("IsHit");

    protected override void Awake()
    {
        base.Awake();
    }

    // Start is called before the first frame update
    void Start()
    {
        controller.OnAttackEvent += Attacking;
        controller.OnMoveEvent += Move;
    }

    private void Attacking(AttackSO sO)
    {
        animator.SetTrigger(Attack);
    }

    private void Move(Vector2 obj)
    {
        animator.SetBool(IsWalking, obj.magnitude > .5f);
    }

    private void Hit()
    {
        animator.SetBool(IsHit, true);
    }

    private void InvincibilityEnd()
    {
        animator.SetBool(IsHit, false);
    }
}

📺 Player → MainSprite에 애니메이션을 추가하자!

Assets에 Animations 폴더를 생성, Player 폴더를 그 밑에 만들고 player_idle 이라는 애니메이션을 생성하자!

이후에 생성한 애니메이션을 MainSprite에 추가한 뒤, Animation Recorder를 연다. (애니메이션 더블 클릭하면 열림)

MainSprite를 선택한 상태에서 Animation Recorder에 캐릭터의 idle 애니메이션 스프라이트를 넣어준다.

애니메이션 스프라이트의 간격을 적당하게 조절한 뒤, 실행을 해보자!!

player_idle은 계속해서 실행되어야 하기 때문에 Loop Time을 체크하자.

같은 방법으로 player_run이라는 애니메이션도 추가하자.

▪️ player_hit

이제 player_hit 이라는 애니메이션을 만들어 보자
플레이어가 맞는 스프라이트를 넣어준 다음, 플레이어가 맞을 때 색상 또한 변경해보자.

Add Property를 통해 SpriteRenderer.Color를 추가한다.

이후 0프레임과 3프레임에 Color를 변경해준다. 둘다 Color.g, Color.b를 0.2로 변경하여 빨간색이 되면 된다.

▪️ player_attack

이제 플레이어가 공격하는 애니메이션을 만들어 보자. 다만 문제점은 현재 플레이어가 공격하는 스프라이트가 없기 때문에 공격할 때 무기가 움직이도록 만들어 볼 것이다.

Recording 버튼을 누른 후, WeaponSprite를 클릭한다. 그리고 WeaponSprite의 position X값과 Scale X값을 변경하면 애니메이션 레코더에 등록이 되는 것을 확인할 수 있다.

등록이 되는 모습.

이후에 0, 3프레임에 Position과 Scale을 원래 값으로 설정한다.

그리고 1, 2프레임에 Position과 Scale 값을 변경한다.
1프레임 ▼

2프레임 ▼

재생해서 확인해본다.

📺 애니메이션 처리

애니메이터 MainSprite를 더블 클릭하여 애니메이터 창을 연다. 그 후, player_attack을 지운다.

그후 Parameters 에서 bool IsWalking, Trigger Attack, bool IsHit을 생성한다.

그 다음, player_idle에서 Make Transition을 통해 player_run을 연결해준다. 그 반대 방향도 추가한다.

이후에 player_idle → player_run으로 가는 트랜지션을 다음과 같이 수정한다.
1. Has Exit Time을 꺼야 idle 애니메이션이 진행 중이어도 바로 run으로 넘어올 수 있다.
2. isWalking이 true가 되면 idle 에서 run으로 애니메이션이 전환된다.

다음으로 player_run에서 player_idle로 되돌아가는 트랜지션을 다음과 같이 수정한다.
1. 마찬가지로 Has Exit Time을 꺼 애니메이션이 바로 전환되도록 설정한다.
2. isWalking이 false가 되면 run에서 idle로 전환된다.

그후 player_idle과 player_hit을 전환하는 트랜잭션을 생성하고 마찬가지로 수정해준다.

▪️ Attack layer 만들기

이후에 애니메이터 창에서 Layers에서 layer를 추가하여 애니메이션을 분리하여 관리할 수 있다.
→ 예시로 손, 몸, 다리의 애니메이션을 각자 만들 경우, 그에 따른 layer를 분리하여 생성하면 편리하다.

우리는 layer를 추가해서 Attack layer를 만들어 스프라이트 애니메이션과 분리하여 관리할 것이다.

Attack layer를 생성한 뒤, 톱니 바퀴를 눌러 Blending을 Additive로, Weight를 1로 변경한다.

그 이후로 Create State → Empty를 생성한다. -> 평상 시에는 애니메이션이 동작하지 않도록 Empty인 상태를 유지해준다.

그리고 player_attack을 추가하여 Any State와 연결한다. -> 어떤 상태였던 간에 Attack이 트리거되면 바로 공격하도록.

Has Exit Time을 끄고, Conditions는 Attack이 트리거 될 때로 설정해준다.

그리고 player_attack과 Exit를 연결하여 공격 애니메이션이 재생되면 종료되도록 설정한다.

이제 Player에게 TopDownAnimationController를 추가해주면 된다.

이제 Loop Time을 체크해주자. player_idle과 player_run은 계속해서 실행이 되어야 하기 때문에 Loop Time을 체크해주고, 나머지는 해제하면 된다.

애니메이션이 정상적으로 작동하는 모습!!! ▼

0개의 댓글