WAIT, I’VE CHANGED MY MIND! STATE MACHINE TRANSITION INTERRUPTIONS (번역)
잠깐, 생각을 바꿨어요! 상태 머신 트랜지션 인터럽트 (번역)
WAIT, I’VE CHANGED MY MIND! STATE MACHINE TRANSITION INTERRUPTIONS
저는 최근에 유니티 사용자가 보고한 복잡한 버그를 살펴봤습니다. 그 버그는 empty state, 레이어 오버라이드, 트랜지션 인터럽트와 관련된 내용이였습니다. 제가 살펴본 결과, 애니메이션 시스템의 트랜지션 인터럽트에 관련된 문서의 내용이 부족하다는 것을 알았습니다. 우리 팀과 오랜 토의 끝에, 블로그 포스트로 올리자는 의견으로 결론 지었습니다.
이제 상태 머신의 트랜지션과 인터럽션에 대해서 자세히 살펴보겠습니다.
기본적으로, 애니메이션 시스템에서 트랜지션은 인터럽트가 동작하지 않습니다: 한 스테이트에서 다른 스테이트로 전환할 때 이를 빠져나올 방법이 없습니다. 대서양을 횡단하는 비행기에 탑승한 승객과 같이, 편안하게 목적지에 도착할 때 까지 앉아 있고, 여러분의 마음을 바꿀 수 없습니다. 대부분의 사용자들에게, 이런 동작방식은 문제가 없습니다.
하지만, 여러분이 트랜지션에 대한 좀 더 세심한 컨트롤을 필요로 하는 경우, 여러분의 요구사항에 맞도록 다양한 방식으로 메카님 설정을 조절할 수 있습니다. 여러분이 현재 여러분의 목적지에 만족하지 않는 경우, 파일럿의 자리로 가서 비행 중간에 계획을 변경할 수 있습니다. 이 말은 좀 더 즉각적으로 반응하는 애니메이션을 의미하지만, 동시에 복잡도가 증가해서 길을 잃을 수도 있다는 의미를 갖습니다.
몇 가지 예제를 통해서 여러가지 경우를 살펴보겠습니다. 먼저 네 개의 상태(state)를 가진 단순한 상태머신부터 시작해 보겠습니다. 각 상태는 A에서 D까지의 이름을 갖고, 모든 트랜지션에는 트리거가 설정되어 있습니다.
기본적으로, A->B 트랜지션의 트리거가 발생하면, 우리의 상태머신은 상태를 B로 전환시키는데 이 경우, 이 전환 과정을 막을 방법이 없습니다. 하지만 A->B 트랜지션을 선택하고 인스펙터 뷰에서 interruption source 값을 “None”에서 “Current State”로 변경하면, A에서 B로 전환되는 과정에서 A상태의 “몇 가지” 트리거를 이용해서 인터럽트를 발생시킬 수 있습니다.
왜 “몇 가지” 일까요? “Ordered Interruption” 체크박스가 기본 값으로 체크되어 있기 때문입니다. 이는 다시말해, A상태의 트랜지션 우선순위가 현재 상태의 우선순위보다 높다는 의미입니다. A상태의 인스펙터 뷰를 살펴보면, A->C 트랜지션에만 적용되는 것을 확인할 수 있습니다.
따라서 A->B 트리거를 발생시키면, A->D 트리거 바로 다음에, 우리의 트랜지션은 인터럽트가 발생되지 않은상태로 남아 있습니다. 하지만, 그 대신 A->C 트리거를 누르면, 트랜지션은 그 즉시 인터럽트가 발생하여 상태 머신은 C상태로 전환을 시작합니다.
내부적으로, 애니메이션 시스템은 인터럽트가 발생한 시점의 포즈(자세)를 저장하고, 정지 자세 (X)-앞에서 저장한 자세-와 새로 설정된 전환 목적지인 C 애니메이션과 블렌딩 합니다.
왜 현재 자세와 새로 설정된 트랜지션 사이를 좀 더 부드럽게 블렌딩하는 대신 정지 자세일까요? 간단히 말해서: 성능 때문입니다. 게임에 다수의 인터럽트가 발생하면, 동시에 발생하는 다이나믹 트랜지션을 추적하느라 애니메이션 시스템이 이 어려움을 극복하지 못하는 경우가 발생할 수 있습니다.
이제, “Ordered Interruption” 체크박스를 해제하면, A->C 와 A->D 트랜지션에서 인터럽트가 발생할 수 있습니다. 하지만, 같은 프레임에 두 개의 트랜지션이 동시에 발생하면, A->C 트랜지션이 우선순위가 높기 때문에, 우선권을 갖습니다.
interruption source 값을 “Next State”로 변경하면, A->C와 A->D 트랜지션은 해당 트랜지션의 순서에서도 더 이상 인터럽트가 발생하지 않습니다. 하지만, B->D 트리거를 누르면, B상태로의 전환이 완료되지 않고 A에서 D로의 트랜지션이 즉시 시작됩니다.
트랜지션 순서는 B 상태에서도 중요합니다. “Ordered Interruption” 체크박스는 더 이상 B 상태에는 소용이 없습니다 (B 상태로의 트랜지션을 발생시키는 트리거는 모두 A->B 와 관련된 우선순위 랭킹을 갖고 있지 않기 때문에, 인터럽트를 발생시킬 수 있습니다). 하지만, 같은 프레임에 트리거가 동시에 발생했을 때, B 상태로의 트랜지션 순서가 어떤 트랜지션이 우선순위를 갖는지를 판정합니다. 이 경우 예를 들어, B->D 와 B->C 가 같은 프레임에 동시에 트리거가 발생하면, B->D가 선택됩니다.
마지막으로, 완전한 컨트롤을 위해서, Interruption Source 값을 “Current State Then Next State” 로 설정하거나, “Next State Then Current State”로 설정할 수 있습니다. 이 경우, 해당 트랜지션은 하나의 상태(state)에서 독립적으로 판정된 후에 다음 상태에서 판정됩니다.
아래 그림과 같이 설정을 했다고 가정해 봅시다.
A->B 트랜지션 도중에, 매우 흥분한 플레이어가 같은 프레임에 네 개의 트랜지션: A->C, A->D, B->C, B-D,을 동시에 발생시킨 경우 어떻게 동작할까요?
첫째로, “Ordered Interruption”이 체크되어 있기 때문에, A->D는 A->B 보다 우선순위 낮기 때문에, 바로 무시할 수 있습니다. 현재 상태는 가장먼저 해결됩니다. 따라서 A->C 트랜지션이 발생할 지를 확인하기 위해서 B상태를 들여다 볼 필요가 없습니다.
하지만, 설정 값이 같을 때, B->C와 B->D 트랜지션만 발생한 경우, B->D 트랜지션이 진행됩니다. (B->C 트랜지션보다 우선순위가 높기 때문입니다.)
다른 모든 트랜지션 역시 각각 설정된 규칙에 따라서 인터럽트가 발생될 수 있습니다. next state에서 A->C 트랜지션이 인터럽트가 가능하게 설정하면, A->C 트랜지션에 의해서 인터럽트가 발생가능한 A->B 트랜지션을 갖게 됩니다. (A->C 트랜지션은 C->D 트랜지션에 의해서 차례로 인터럽트가 발생될 수 있습니다)
여기서 명심해야 할 것이 있습니다: 인터럽트 발생 여부에 관계없이, source 상태(state)는 해당 트랜지션이 완료될 때까지 같은 상태로 남아있고, Animator.GetCurrentAnimatorStateInfo() 메소드는 항상 그 source 상태를 반환합니다.
요약 하면, 트랜지션 인터럽트 설정은 매우 강력하고 다양하게 응용될 수 있는 기능을 제공하지만, 혼란스러워 질 수 있습니다. 따라서 트랜지션 인터럽트를 현명하게 사용하시기 바라며, 의심되는 경우, 에디터에서 테스트를 먼저 진행하시기 바랍니다.
이 저작물은 크리에이티브 커먼즈 저작자표시-비영리-변경금지 2.0 대한민국 라이선스에 따라 이용할 수 있습니다.