이번 포스팅은 저번 포스팅과 이어진다. 저번에는 버튼의 움직이는 기능들을 중점적으로 살펴보았는데, 그 중에서도 AttackButton은 아무런 기능없이 남겨두었다. 이번에 애니메이션을 만들면서 진짜로 슬라임이 공격하게끔 해보아야겠다.
이번 포스팅에서 배울 것은
->Animator / Animation 작성 방법(의외로 쓰다보니 양이 많아서 이것만 다루기로 했다.)
나도 아직 완벽하게 이 애니메이션의 작동방식이나 동작 의도를 파악하지는 못했지만, 이렇게 내가 알아낸 방법들을 적어보려고 한다. 우선 애니메이션을 생성할 기틀을 만들어야한다. 만들어둔 Asset/Animation폴더에 들어가서, 아래 처럼 Animation Controller(Animator)와 Animation을 만들어 준다.
컨트롤러는 한 개, 애니메이션은 각각의 상태에서 보일 애니메이션의 개수에 따라서 적절히 조절하면 된다. 이렇게 만들어 두었다면 Slime의 인스펙터에서 Animator를 한개 찾아서 더해준다.(Animation 아니라 Animator)
그리고 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을 제어할 수 있게 된다.
여기서 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을 만들어서 애니메이션을 지속할 수 있게 할 수도 있다. 이 부분을 구현하는 것은 본인 자유에 맡기겠다.)
이제 슬슬 눈치 챘겠지만 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(영상 속에 새로 등장한 캐릭터)을 공격하는 기능을 넣어보록 하자.
'프로그래밍 > Unity' 카테고리의 다른 글
Unity - Drag & Drop - How to make Post (2) | 2021.11.25 |
---|---|
Unity - Coroutine(코루틴) - Reference Post (0) | 2021.08.13 |
내가 유니티에선 왕초보? - 4주차 - 레이어와 Hp (0) | 2021.05.08 |
내가 유니티에선 왕초보? - 2주차 - 움직여보기 (0) | 2021.05.07 |
내가 유니티에선 왕초보? - 1주차 - 기본기 (0) | 2021.04.03 |