본문 바로가기
프로그래밍/Unity

내가 유니티에선 왕초보? - 3주차 - 애니메이션

by 리나그(ReenAG) 2021. 5. 7.
728x90
반응형

passingprogram.tistory.com/27

 

코딩에선 초보가 아닌 내가 유니티에선 왕초보? - 2주차 - 움직여보기

휴... 지난번에 달랑 한번하고 포스팅을 하지 않았더니 완전 감각이 다 죽어버렸을지도 모르겠다. 결국 뭐든지 열심히 해야지 느는 건데... ㅠㅠ 오늘 실수로 스터디에 늦어버렸다. 밥먹고 나니

passingprogram.tistory.com

이번 포스팅은 저번 포스팅과 이어진다. 저번에는 버튼의 움직이는 기능들을 중점적으로 살펴보았는데, 그 중에서도 AttackButton은 아무런 기능없이 남겨두었다. 이번에 애니메이션을 만들면서 진짜로 슬라임이 공격하게끔 해보아야겠다.

 

이번 포스팅에서 배울 것은

->Animator / Animation 작성 방법(의외로 쓰다보니 양이 많아서 이것만 다루기로 했다.)

 

나도 아직 완벽하게 이 애니메이션의 작동방식이나 동작 의도를 파악하지는 못했지만, 이렇게 내가 알아낸 방법들을 적어보려고 한다. 우선 애니메이션을 생성할 기틀을 만들어야한다. 만들어둔 Asset/Animation폴더에 들어가서, 아래 처럼 Animation Controller(Animator)와 Animation을 만들어 준다.

컨트롤러는 한 개, 애니메이션은 각각의 상태에서 보일 애니메이션의 개수에 따라서 적절히 조절하면 된다. 이렇게 만들어 두었다면 Slime의 인스펙터에서 Animator를 한개 찾아서 더해준다.(Animation 아니라 Animator)

 

Controller에 Slime을 넣는다.

그리고 Animator와 Animation창이 필요할텐데... 아마 처음에는 이 창이 없을 수도 있다. 위의 것들을 더블클릭해도 아무것도 나오지 않는다면, Window옵션에 들어가서 필요한 창을 찾아야 한다.(나도 정확히 어떻게 했는지는 모르겠다.) 아무튼 그렇게 창을 찾아냈다면, 이런게 하나 있을 것이다.

Any State, Entry, Exit는 움직일 수 있는 아이들이다. 위치가 약간 다른 이유는 내가 약간 옮겨 놓았기 때문이다. 이것들이 무슨 역할을 하는지를 알기 위해서는 우리가 만든 애니메이션도 필요하다. 우선, 기존에 만들었던 Slime_Idle 애니메이션을 먼저 드래그 앤 드롭하고, 나머지를 전부 드래그 앤 드롭하자. 대강 이렇게 된다 :

위치들은 각자 보기 편하게 조절하자.

Entry는 처음에 애니메이션이 시작되었을 때 그곳에서 무조건 지정 되어있는 Default Transition해당하는 Animation을 실행시킨다. 여러분이 만들지도 않았는데 Slime_Idle에 지정되어 있는 노란색 화살표가 Default Transition인데, 이 녀석은 조절할 수 있는 옵션이 삭제고 뭐고 없다. 시작하자마자 Slime_Idle을 실행하기 위함인 듯 하다. 굳이 Idle을 먼저 드랍하라고 한 이유도 우선 게임이 시작되었다면 보통 캐릭터는 멈춰있기 때문에 그 애니메이션을 실행하기 위해서 이다. 그럼, 왼쪽의 리스트에 3개의 변수를 만들어 두자.

+버튼을 눌러서 특정 타입의 변수를 만들 수 있다.

Trigger와 Bool은 비슷하지만, Trigger는 한번 실행 된 후에는 알아서 False가 되는 반면, Bool은 그대로 남아 있다는 차이가 있다. Attack은 다시 Attack을 하기 전까지는 애니메이션을 다시 실행시킬 이유가 없으므로 Trigger, 나머지 동작들은 다시 그 동작을 멈추기 전까지는 계속해서 애니메이션을 실행해야하기 때문에 Bool을 이용한다. 물론 Integer 등을 이용해도 괜찮다.

 

그 이후에는 Transition을 우리가 직접 만들어야한다. 마우스 오른쪽 버튼 -> Make Transition 옵션을 이용해서 아래와 같이 맵을 만들어 두자.

우선은 화살표 방향만 제대로 되면 장땡이다!

이렇게 화살표가 짜이면 된다. 특히 방향은 중요하니까 신경쓰시길! 그럼, 그 화살표중에 1개 Slime_Idle -> Slime_Move로 가는 화살표를 클릭해보자. 오른쪽 Inspector를 통해서 이 transition을 제어할 수 있게 된다.

오른쪽의 Inspector에 주목!

여기서 Has Exit Time을 제거하고, 아래의 Conditions에 가서 Moving - true와 Jumping - False를 추가해준다.

Has Exit Time의 조건을 해제하면, 현재 애니메이션이 Slime_Idle 상태의 애니메이션이 끝나지 않았더라도 강제로 Slime_Move로 옮겨갈 수 있다. 다만 그렇게 옮겨가려면 조건을 달아주어야 한다. 여기선 Animator의 Moving이라는 변수가 true이고 Jumping이 False일 때 옮겨가는 것으로 설정한 것이다. (Jumping이 false여야하는 이유는 움직이면서 점프할 때, 점프 중의 모션을 우선적으로 이용하고 싶기 때문이다.)

 

이 화살표 말고도 AnyState -> Slime_Attack과 Slime_Idle -> Slime_Jump로 갈 때도 비슷하게 조건을 설정해 준다. 나머지 화살표는 아직 건드릴 필요는 없다.(원한다면 Slime_Jump->Slime_Jump transition을 만들어서 애니메이션을 지속할 수 있게 할 수도 있다. 이 부분을 구현하는 것은 본인 자유에 맡기겠다.)

Slime_Idle -> Slime_Jump
Any State -> Slime_Attack

이제 슬슬 눈치 챘겠지만 Any State는 애니메이션이 어디서 실행 중이던지 싹 무시하고 조건만 맞는다면 Slime_Attack 애니메이션을 실시한다. 그래서, 조커카드 같다는 느낌을 준다. 아마 프로그래머라면 알겠지만, 강제로 흐름을 끊고 건너뛰는 스파게티 코드는 좋지 않다. 배운 적은 없지만, Any State를 남용하면 분명 문제가 생길 듯 싶다. (그래도 이런 작은 애니메이션에 쓰는 거 정도는 괜찮을 듯.)

 

그럼, Slime을 애니메이터에 넣어놓았으니, Slime을 Hierarchy창에서 지정한 상태로 Animation 창을 들여다보자. 우선, Slime_Jump상태의 에니메이션을 우선 제작할 것이므로 Perview아래의 드롭다운 메뉴를 Slime_Jump로 바꾸자. 그리고 Add Preperty를 누른다.

(나는 이미 Add Property를 이용해서 만들어 두었다.) 거기서 SpriteRender의 제일~ 아래에 있는 Sprite라는 옵션을 가져오자. 그렇게 한 다음 아이콘 옆의 작은 화살표를 누르면 현재 애니메이션으로 쓰일 스프라이트가 오른쪽에 보인다.

각 초에 쓰일 만한 스프라이트를 드래그 앤 드롭한다.

그 후에는 위의 화면에서 보이는대로, 원하는 순간에 스프라이트를 집어넣어서 애니메이션을 만들면 된다. 나머지 Slime_Attack, Slime_Move도 비슷하게 애니메이션을 손수 제작해주자.(Idle 모션을 넣어도 되지만 생략)

 

애니메이션 다 만든 결과:

그렇게 한 다음 Slime.cs를 바꾼다. 애니메이터를 가져오고, 거기에 생성해 두었던 Attack, Moving, Jumping등의 변수를 직접 제어할 수 있게 바꾸어야한다.

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

public class Silme : MonoBehaviour
{

    [SerializeField] public float speed;
    [SerializeField] public float jumpforce;
    public Vector2 presistAddVelocity;
    private Rigidbody2D rigidBody;
    private Animator animator;
    public bool is_jumping;

    // Start is called before the first frame update
    void Start()
    {
    	//애니메이터도 내부 변수로 가지고 와준다.
        rigidBody = this.GetComponent<Rigidbody2D>();
        animator = this.GetComponent<Animator>();
        presistAddVelocity = new Vector2(0, 0);
        is_jumping = false;
    }

    // Update is called once per frame
    void Update()
    {
        rigidBody.velocity = presistAddVelocity * speed + rigidBody.velocity;
        //여기서 두 개의 변수를 초기화 한다.
        animator.SetBool("Moving", presistAddVelocity != Vector2.zero);
        animator.SetBool("Jumping", is_jumping);
    }

    public void Jump(){
        Vector2 jumpVec = is_jumping ? Vector2.zero : new Vector2(0, jumpforce);
        rigidBody.AddForce(jumpVec, ForceMode2D.Impulse);
    }

    public void Attack_Start(){
        animator.SetTrigger("Attack");
    }

    public void Attack_Stop(){

    }

	//이전과 달리 Floor (6)에만 초기화를 해주는 이유는 Man이라는 새로운 오브젝트 때문이다.
    private void OnCollisionStay2D(Collision2D collision2D){
        if(collision2D.gameObject.name == "Floor (6)")
            is_jumping = false;
    }

    private void OnCollisionExit2D(Collision2D collision2D){
        if(collision2D.gameObject.name == "Floor (6)")
            is_jumping = true;
    }

}

자 이렇게 하면 기본적인 애니메이션 실행은 할 수 있다. animator.SetBool, SetTrigger등을 이용해서 방금 전에 우리가 생성했던 변수를 제어할 수 있게 된다. (SlimeBtn은 바꿀 필요 없다.)

 

결과 :

아직은 Attack에 쿨타임이 없다. 그래서 저렇게 여러 번 공격이 나가는 것이다. 아무튼 대강 어떻게 애니메이션을 적용하는지 알아보았다. 다음 차시에는 실제로 Man(영상 속에 새로 등장한 캐릭터)을 공격하는 기능을 넣어보록 하자.

728x90
반응형