티스토리 뷰

 

한참이 지난 후,  WaitWhile 과 WaitUntil을 알게 되었습니다. 이에 수정합니다.

 

수정 전 글의 방식은 매 프레임마다 애니메이션이 끝났는지 확인하는 코드입니다.

틀린 코드인 것은 아닙니다.

매프레임마다 처리해야 할 일이 있다면

yield return null 이나 yield return new WaitForFixedUpdate 같이

프레임마다 재생상태를 검사해야하는 것은 맞습니다.

 

하지만 단순히 재생이 완료되었는지를 확인하는 거라면

WaitUntil 과 WaitWhile 을 사용하면 됩니다.

 

    IEnumerator EndFrameEvent()
    {
        Animator anim = GetComponent<Animator>();
		
        //매 프레임 단위로 while 문을 반복하여 애니메이션의 재생 상태를 확인한다.
        while (anim.GetCurrentAnimatorStateInfo(0).normalizedTime < 1) yield return null;

        print("애니메이션 클립 재생 완료");
    }


    IEnumerator EndFrameEvent()
    {
        Animator anim = GetComponent<Animator>();
		
        // 조건식이 참인 동안 코루틴의 처리를 미룹니다.
        yield return new WaitWhile(() => anim.GetCurrentAnimatorStateInfo(0).normalizedTime < 1);
        
        print("애니메이션 클립 재생 완료");
    }


    IEnumerator EndFrameEvent()
    {
        Animator anim = GetComponent<Animator>();
		
        // 조건식이 참이 될 때까지 코루틴의 처리를 미룹니다.
        yield return new WaitUntil(()=>anim.GetCurrentAnimatorStateInfo(0).normalizedTime >= 1f);

        print("애니메이션 클립 재생 완료");
    }

 

 

 

코루틴도 코루틴이지만 중요한 것은 

 

GetcurrentAnimatorStateInfo 로 애니메이션의 재생 상태를 얻을 수 있다는 것이다.

 


 

 

 

Unity - 스크립팅 API: Animator

Success! Thank you for helping us improve the quality of Unity Documentation. Although we cannot accept all submissions, we do read each suggested change from our users and will make updates where applicable. 닫기

docs.unity3d.com

 

유니티에서 게임을 만들 때면 특정 오브젝트의 애니메이션이 끝나는 순간을 노려 함수를 호출하는 경우가 많다. 

이전에는 그 애니메이션의 원하는 프레임에 Event를 넣어주곤 했지만

아래의 방식이 손이 덜 가서 자주 애용한다. 

GetcurrentAnimatorStateInfo를 사용하는 것인데,

사용 예는 이렇다.

 

    IEnumerator WaitWhileAnimPlaying()
    {
        GetComponent<Animator>().SetTrigger("Next");

        while (GetComponent<Animator>().GetCurrentAnimatorStateInfo(0).IsName("Anim 1"))
        {
            yield return null;
        }

        print("Animation is Ended");
    }

 

while문의 조건부에 Animator가 현재 재생 중인 애니메이션을 체크하여 

(알맞은 표현인진 모르겠지만) 코루틴을 while문에 잡아 두는 것이다.

하지만 SetTrigger 직후에 바로 while문을 쓰려니

while문의 차례엔 아직 다음 애니메이션이 재생되지가 않는 것인지 while문을 가볍게 지나치는 것이다.

혹시나 Transition 때문에 그런 것인가 고민도 해봤다.

"anim 1에서 anim 2로 넘어가는 과정에서 while문이 anim 1의 재생을 확인하고 while문을 마쳐버린 것이다."

라고 생각한 것이다.

때문에 anim 1과 anim 2가 겹쳐진 Duration 길이만큼 코루틴을 쉬어주면 모르겠는데

일일이 그 시간을 조건으로 걸어주기 귀찮으니 코딩의 줄을 늘려버리기로 했다.

 

    IEnumerator WaitWhileAnimPlaying()
    {
        GetComponent<Animator>().SetTrigger("Next");

        while (GetComponent<Animator>().GetCurrentAnimatorStateInfo(0).IsName("Anim 1") 
        || GetComponent<Animator>().GetCurrentAnimatorStateInfo(0).IsName("Anim 2"))
        {
            yield return null;
        }

        print("Animation 0 is Ended");
    }

 

이게 무슨 꼴이냐면 while문에서 anim 1가 재생 중이거나( || ) anim 2가 재생 중이라면 while문을 다시 반복시키도록 적어둔 것이다.

이게 가독성이 장난 아니게 안 좋다


한 가지 더,

애니메이션의 특정 부분에서 원하는 함수를 불러내는데 키프레임 이벤트를 사용하는 것도 유용한 방법이지만,

일일이 그 객체에 스크립트를 달아주는 것은 귀찮은 작업이다.

이때에도 GetcurrentAnimatorStateInfo를 활용할 수 있는데,

 

        while (GetComponent<Animator>().GetCurrentAnimatorStateInfo(0).IsName("Anim 2"))
        {
            if(GetComponent<Animator>().GetCurrentAnimatorStateInfo(0).normalizedTime > .5f)
            {
                break;
            }
            yield return null;
        }

 

normalizedTime를 사용하여 현재 애니메이션이 얼마큼 재생되었는지 정도를 알 수 있다.

 

https://docs.unity3d.com/kr/530/ScriptReference/AnimationState-normalizedTime.html

 

Unity - 스크립팅 API: AnimationState.normalizedTime

Success! Thank you for helping us improve the quality of Unity Documentation. Although we cannot accept all submissions, we do read each suggested change from our users and will make updates where applicable. 닫기

docs.unity3d.com

 

normalizedTime은 애니메이션의 길이를 1로 정규화한 값을 나타내므로

만약에 "Anim 2"이 10초 길이의 애니메이션 클립이라면,

상기한 코드에서 .5f 는 50%, 즉 애니메이션이 약 5초 재생된 시점에서 while 문을 break 하는 것이다.

일단, 이 정도만 사용해도 간단한 게임에선 원하는 타이밍을 잡기 매우 수월해지는 것 같다.  

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/09   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
글 보관함