-
애니메이션과 스킬 타이밍 동기화, 근데 AnimatorStateInfo를 곁들인..게임 클라이언트 개발/MakeDNF 2024. 1. 31. 17:05
캐릭터의 스킬에는 여러 타이밍이 존재한다. 선딜레이가 끝나는 시점, 히트박스가 켜지고 꺼지는 시점 등 다양한 타이밍이 존재하는데, 기본 공격을 구현하면서 이러한 타이밍을 어떻게 컨트롤했는지에 대해 작성해보고자 한다.
Time.DeltaTime을 활용한 시간 계산
처음으로 시도한 방법으로, 스크립트에서 시간 계산을 통해 타이밍을 설정했다. 애니메이션 클립의 프레임 수와 재생 속도 등 여러 변수들을 고려하여 선딜레이나, 후딜레이 등 각 시점을 정하고 Update를 통해 상태 변화를 구현했다.
public override void OnStart() { attackSpeed = character.Animator.GetFloat(attackSpeedHash); // 타이밍 계산 로직 : 한 프레임 시간 * 각 상태의 클립 수 * 애니메이션 Speed * 애니메이션 multiplier preDelay = Time.deltaTime * 1f * 4f * attackSpeed; postDelay = Time.deltaTime * 1f * 4f * attackSpeed; } public override void OnUpdate() { timer += Time.deltaTime; switch (phase) { case EStatePhase.PREDELAY: if (timer < preDelay) return; // Change the state to HITBOXACTIVE... break; case EStatePhase.POSTDELAY: if (timer < postDelay) return; // Finish the skill... break; // Extra state ... } }
다만, 해당 방법을 사용할 경우 애니메이션의 속도가 바뀔 때마다 스크립트를 수정해야 했다. 그리고 캐릭터의 공격 속도 매개변수인 AttackSpeed의 값이 어떻게 바뀔지 모르기 때문에 OnStart 함수에서 계속 갱신해야 했다. 또한 애니메이션의 속도의 역수를 곱해주는데 해당 값이 float 타입이고 이진수로 정확히 표현할 수 없는 값이라면 (0.3일 경우 역수는 10 / 3이 된다), 오차값이 발생하여 애니메이션의 정확한 타이밍을 검출하기가 매우 까다로웠다.
Animation Clip Event
또 다른 방법으로 애니메이션 클립에 이벤트 함수를 할당하는 방법을 시도했다. 원하는 프레임에 이벤트 함수를 호출하여 정확한 타이밍을 계산할 수 있기를 기대했다.
단, 해당 방법을 사용할 경우 애니메이션 클립에 이벤트를 할당하게 되어, 다른 애니메이션에 해당 클립을 재사용할 수 없었다.
AnimatorStateInfo
마지막 방법으로 AnimatorStateInfo를 활용하여 타이밍을 설정했다. Animator 컴포넌트에서 GetCurrentAnimatorStateInfo(int layer) 함수를 통해 현재 실행 중인 애니메이션의 State를 AnimatorStateInfo 타입의 변수로 가져올 수 있다. AnimatorStateInfo의 IsName(string stateName)과 normalizedTime를 활용하여 현재 애니메이션의 타이밍을 알 수 있었다.
public override void OnUpdate() { AnimatorStateInfo animatorStateInfo = character.Animator.GetCurrentAnimatorStateInfo(0); switch (phase) { case EStatePhase.PREDELAY: if (!animatorStateInfo.IsName("BaseAttack_1")) return; // Change the state to HITBOXACTIVE... break; case EStatePhase.POSTDELAY: if (!animatorStateInfo.IsName("BaseAttack_1_End")) return; if (animatorStateInfo.normalizedTime < 1f) return; // Finish the skill... break; // Extra state ... } }
Unity의 이벤트 함수 실행 순서를 확인해 보면, Update 로직이 애니메이션 로직보다 먼저 실행되기 때문에 nomalizedTime만을 활용할 경우 애니메이션이 업데이트가 되지 않았다. 그래서 IsName(string stateName)을 추가로 사용했고, 이에 따라 string 타입 비교가 추가되었으며 오타의 위험성이 발생했다. 그럼에도 정확한 타이밍을 추출할 수 있고, 프레임 수를 계산하기에 용이했다.
'게임 클라이언트 개발 > MakeDNF' 카테고리의 다른 글
스킬 범위... 어떻게 설정하지...?? with. 반월 (0) 2024.02.02 악즉참 스킬로 알아보는 역경직 발생 조건 (0) 2024.02.01 남 넨마스터의 넨가드 스킬에 대한 고찰 (0) 2024.01.22 Object Pooling을 위한 Tool 제작 (0) 2024.01.11 Hitbox와 Hitbox Editor 개선 (0) 2024.01.11