호우동의 개발일지

Today :

article thumbnail

크립트 상에서 현재 애니메이션 상태를 받아오는 방법으로
가장 대표적인 것은 Animator 컴포넌트의 GetCurrentAnimatorStateInfo
이용하는 방법이다.


여기서 가장 많이 보편적으로 사용하는 함수를 설명하겠다.

자주 쓰이는 함수
자주 쓰이는 함수

 

해당 함수를 이용해서 아래 구현 목표에 해당되는 보스 스킬을 구현해 보겠다.

 

 


구현 목표

구현 기획도
500

음.. 이상하게 보이긴 하지만
보스가 스프링처럼 몸을 움츠리는 애니메이션을 하고 그 사이에 빨간 구는 점점 커진다.


그리고 보스가 한 번에 튀어 오르면서
커진 빨간 구가 위로 발사되는 보스 패턴을 만들 것이다.

여기서 빨간 구가 커지는 타이밍과 보스 애니메이션이 연관됐고,
위로 발사되는 타이밍도 보스 애니메이션이
튀어 오르는 타이밍에 발사되어야 하기 때문에
 
스크립트상에서 이 타이밍을 맞춰줘야 한다.

 

 


구현 과정


1. 보스 액션 애니메이팅

일단 스프링처럼 몸을 움츠렸다가 위로 튀어 오르는 애니메이션을 만들어보자.

애니메이션 인스펙터
애니메이션 인스페거에서 새로운 애니메이션 만들기

만들고자 하는 오브젝트를 클릭하고 Animation 창에서
Create New Clip으로 새로운 Animation을 만들었다.


필자는 Bishop_Rage라는 이름으로 애니메이션을 만들었다.
왜냐하면 이 패턴은 피가 얼마 남지 않았을 때 광폭화 패턴으로 만들 것이기 때문이다.

스프링 액션 만들기
스프링 애니메이션 만들기

스프링처럼 구부렸다가 펴는 애니메이션은 Scale에 Y축을 조절하는 방식으로 만들었다.
그래서 Add Property를 통해 Scale을 불러주고 조작하는 방식을 사용했다.

 

애니메이션 제작 과정
애니메이션 제작 과정

왼쪽 위에 빨간 원 버튼을 누르고 스케일을 조절하면 정해진
프레임과 프레임 사이의 스케일을 자연스럽게 연결시켜 준다.


여기에 관해서는 예전에 포스팅해 둔 글이 있기 때문에 링크를 달아두겠다.
https://howudong.tistory.com/94

 

[Unity 3D] #4 텔레포트 구현 및 애니메이팅 - Avoid Chess Project

구현 목표 비숍 보스에 텔레포트 패턴을 추가하려고 한다. 텔레포트 패턴은 뿅하고 사라진 후 플레이어의 머리 위에서 나타나는 패턴이다. 구현을 2가지 항목으로 세분화 하였다. 1. 텔레포트 액

howudong.tistory.com

약간 최소 크기까지 줄어든 후 스프링처럼 부들대는 효과를 주기 위해
일정시간 동안 일정 스케일을 왔다 갔다 하게 했다.

완성된 애니메이션은 이렇게 된다.

위에 빨간 공이 없으니까 아직은 어설픈 느낌인데,
일단 빨간 공을 만들어보자. 그래도 어색하면 좀 더 수정하자.

 


2. 애니메이터 연결 및 스크립트 연결

이제 애니메이션은 다 만들었으니까
이제 애니메이션 컨트롤로 넘어가서 다른 애니메이션과 상호작용해 보도록 하자

애니메이터 파라미터 지정
애니메이터 파라미터 지정

해당 액션은 한 번씩만 동작하는 단발성으로 사용할 것이기 때문에 Trigger 형식이면 충분하다.


Trigger는 한번 애니메이션이 실행된 후 연결된 Transition
즉, 화살표에 따라 애니메이션이 전환된다. 
이것이 Bool형과의 차이점이다.

여하튼, Trigger형으로 선언해 주고 이름은 Rage로 선언해 줬다.

애니메이터 연결
애니메이터 연결
애니메이터 연결

어떤 상태에서는 Rage 애니메이션으로 전환될 수 있도록
Teleport 애니메이션일 때와 Idle 애니메이션일 때를 모두 연결한다.


Rage 애니메이션 이후에는 무조건 Bishop_Idle로 돌아가도록 설정한다.

그리고 오른쪽 그림처럼 Bishop_Rage로 향하는 Transition을 다중선택하여 Condition을
아까 만들어뒀던 파라미터인 Rage로 설정한다.

protected override void Enraged()
{
    base.Enraged();
    anim.SetTrigger("Rage");
}

이 광폭화하는 보스패턴의 이름을 공통적으로 Enraged라고 했다. 

다른 건 신경 쓸 필요 없고,
anim.SetTrigger("Rage"); 만 신경 쓰면 된다.

Rage라는 이름의 파라미터를 작동시키는 것이다.  
이러면 Bishop_Rage 애니메이션이 작동한다.

 


3. 빨간 공 이펙트 시간에 따라 커지게 만들기

일단 무료 에셋 이펙트 중에서 적절한걸 고르고
스케일을 조절할 수 있도록 파티클 시스템을 설정하자.

파티클 시스템 스케일모드 변경
파티클을 사이즈를 변경할 수 있게 스케일 모드를 변경한다.

간단하다.
Inspector 창에 있는 Particle System에서 Scaling
Mode를 Hierarchy로 바꿔주면 된다.
이렇게 하면 게임 오브젝트의 스케일 크기에 따라 조절된다.

이제 빨간 공 이펙트에 대한 설정은 끝났고 오브젝트를 만들고 구현해 보자.

이펙트를 한 곳에 모은다.
이펙트를 한 곳에 모은다.

MagicCloud라는 빈 오브젝트 안에 RedBall이라는 이름으로 담았다.


RedBall 3개의 자식오브젝트는 실질적인 RedBall 이펙트이다.
RedBall은 이 3개의 파티클 시스템을 한 곳에 모아둔 빈 오브젝트에 불과하다.

이렇게 MagicCloud안에 모아둔 이유는 빨간 공을 위로 올리고 끝내는 것뿐만 아니라
나중에 번개가 떨어지는 패턴도
 추가할 것이 거서 이렇게 묶어놨다.

이에 관해서는 다음 포스팅에서 다루겠다.
이제 스크립트로 넘어가 보자.

public class Boss_Bishop : ABoss
{
	[SerializeField] MagicCloud magicCloud;
    
	protected override void Enraged()
    {
        base.Enraged();
        magicCloud.gameObject.SetActive(true);
        magicCloud.transform.SetParent(null); // magicCloud의 부모관계를 해제
        anim.SetTrigger("Rage");
    }
}

magicCloud를 Inspector상에서 참조가능하도록 한 후
Enraged가 되면 magicCloud를 활성화하고 magicCloud의 부모관계를 해제한다.

magicCloud의 부모는 Bishop 보스이다. 해제하는 이유는 뭘까?


해제하지 않으면 상대좌표를 따라가기 때문에
보스가 움직일 때 공이 따라서 움직이게 된다.


그래서 의도치 않은 움직임이 생기기 때문에 그런 불상사를 막기 위해
magicCloud의 부모관계를 해제해 주는 것이다.

이제 magicCloud 오브젝트가 활성화되면서 RedBall도 활성화된다.
이제 빨간 공이 커지게 만들어보자.

일단 새로운 스크립트 MagicCloud.cs를 만들었다.

public class MagicCloud : MonoBehaviour
{
	[SerializeField] GameObject redBall;
	private const float CLOUD_EXTEND_RATIO = 1.02F;
    
    void Update()
    {
    	redBall.transform.localScale *= CLOUD_EXTEND_RATIO;
    }
}

방법은 정말 간단하다.


참조로 받은 redBall 오브젝트의 localScale에
임의로 정해준 값을 프레임마다 계속 곱해준다.


그런데 우리가 원하는 건
보스가 튀어 오르는 애니메이션 전까지만 공이 커지는 것이다.

게다가 이렇게 커지면 공이 커지긴 커지는데
공이 보스를 가리게 되면서 이쁘지 않은 그림이 된다.

이를 위에서 언급했듯이 애니메이션 상태를 활용하여 스크립트를 짜보자.

 


4. 빨간 공과 애니메이션 상태 상호작용

public class MagicCloud : MonoBehaviour
{
    [SerializeField] Animator anim;
    [SerializeField] GameObject redBall;
    private const float UP_SPEED = 5F; // 공이 빠르게 올라가는 속도
    private const float CLOUD_EXTEND_RATIO = 1.02F; // 공이 커지는 비율
    private const float OFFSET = 1.01F; // 커질때 조금씩 올라가는 속도 비율
    
    private float cntUpSpeed;
    
    void Update()
    {
        if (transform.position.y > 200f) return;
        if (anim.GetCurrentAnimatorStateInfo(0).IsName("Bishop_Rage") &&
            anim.GetCurrentAnimatorStateInfo(0).normalizedTime < 0.95f)
        {
            redBall.transform.localScale *= CLOUD_EXTEND_RATIO;
            transform.Translate(Vector3.up * cntUpSpeed);
            cntUpSpeed *= OFFSET;
        }
        else transform.Translate(Vector3.up * UP_SPEED);
    }
}

GetCurrentAnimatorStateInfo(0)을 사용한 부분을 해석하자면,


현재 재생 중인 애니메이션이 Bishop_Rage이고,
그 애니메이션의 재생시간이 95% 미만일 때


if문 안의 스크립트를 실행하는 것이다.

여기서 조금씩 공을 올려주는 이유는 공이 커지면서
보스를 조금씩 가릴 테니 그 커지는 만큼 올려주는 것이다.


그리고 그 비율은 곱연산으로 커지니
cntUpSpeed 또한 곱연산으로 커지게 만든다.

그리고 더 이상 Bishop_Rage상태가 아닐 때,
즉 Bishop_Rage애니메이션이 끝나면 공을 위로 쏜다.

이제 스크립트 구현은 끝났으니 인스펙터 설정을 하겠다.

스크립트에 직접 참조
스크립트에 필요한 오브젝트들을 넣는다.

Magic Cloud 스크립트에 직접 참조가 가능하게 해 놨으니
Anim에는 Black Bishop을 넣어 Bishop의 애니메이터를 받을 수 있게 한다.
그리고 RedBall에는 아까 만들어뒀던 RedBall을 넣는다.

 


5. 보스 상태 애니메이션 상호작용

진짜 마지막으로 보스 상태를 애니메이션의 상태와 상호작용해 보도록 하겠다.


보스가 공을 쏘는 타이밍에는 움직일 수가 없기 때문에
플레이어에게 너무 무방비해서 
게임이 쉬워질 수가 있다.

 
그래서 보스가 공을 쏠 때는 무적상태로 만들고 
공을 쏜 직후에는 다시 원래상태로 돌아오도록 구현한다.

protected override void Enraged()
    {
        base.Enraged();
        magicCloud.gameObject.SetActive(true);
        magicCloud.transform.SetParent(null);
        anim.SetTrigger("Rage");
        StartCoroutine(ChangeState());
    }
    private IEnumerator ChangeState()
    {
        gameObject.layer = LayerMask.NameToLayer("Invincibility");
        yield return new WaitUntil(
            () => anim.GetCurrentAnimatorStateInfo(0).IsName("Bishop_Rage")
            && anim.GetCurrentAnimatorStateInfo(0).normalizedTime >= 0.9f);
        gameObject.layer = LayerMask.NameToLayer("Enemy");
        bossState = BossState.idle;
        Invoke("OnAction", actionDelay);
    }

ChangeState라는 코루틴을 추가해 줬다.
레이어를 Invincibility로 만들어준다.

이거는 내가 추가로 만들어준 건데
그냥 다른 레이어랑은 아무런 충돌이 일어나지 않게 만들어놔서 말 그대로 무적상태가 된다.
이걸 yield return new WaitUntil을 사용해서 대기하도록 한다.

yield return new WaitUntil()은 코루틴에서
해당 람다식이 true가 될 때까지 해당 코루틴을 대기시킨다.

즉, 여기서는 Bishop_Rage 애니메이션의 진행이 90% 이상이 되기 전까지 대기한다.


이후 다시 레이어를 원래 상태로 되돌리고 BossState도 원상태로,
그리고 다음 액션을 준비하도록 한다.


구현 결과


구현 결과
구현 결과

나름 괜찮은 애니메이션이 나온 것 같다.
다음 포스팅에서는 다음 패턴과 세트가 되는 번개가 떨어지는 패턴을 구현하겠다.

원래는 같은 포스팅에서 다루려고 했으나,
너무 포스팅이 길어지고 내용이 섞일 것 같아서 따로 다루도록 하겠다.