안녕하세요.
이번에도 확실치 않은 부분이라 조심스럽게 질문을 드립니다. (덜덜)
간단하게 질문을 드리자면
한번에 여러 종류의 애니메이션 요청이 발생하면
애니메이션이 굳어버리는 문제가 발생하는 것 같습니다.
저는 Idle 애니메이션과 Move 애니메이션을 FixedUpdate과 bool 변수를 이용하여 제어합니다.
ex)
FixedUpdate()
{
if(autoAnimeMode == true)
{
PlayIdleOrMoveAnime();
}
}
이런 상황에서 특정 이벤트가 발생했을 때 (피격, 넉다운 등)
autoAnimeMode를 false로 하고
다른 애니메이션을 실행시키는 방식을 사용하는데,
정말 가끔씩 애니메이션이 씹히는(?) 혹은 굳는(?) 경우가 발생했습니다.
그래서 여러가지를 실험하다
여러 상황의 애니메이션이 한번에 요청되어 그러는게 아닐까 싶어
조건들을 추가하여
가능한 한번에 발생 할 수 있는 애니메이션 요청들을 적게 발생 할 수 있게 해봤습니다.
(그래봤자 3개에서 2개로 변한...)
그랬더니 애니메이션이 씹히는 문제가 줄어들더군요.
그래서 혹시나 해서...
특정 이벤트에서 Side_HitDown_Before 애니메이션을 실행할 때
void PlayHitDown()
{
// 테스트
currentAnimeData = portrait.Play("Side_FrontOneHandSkillCharge");
currentAnimeData = portrait.Play("Back_FrontOneHandSkillCharge");
currentAnimeData = portrait.Play("Front_WeaponStabReady");
currentAnimeData = portrait.Play("Side_HitDown_Before");
}
이런식으로 연속으로 실행해 봤더니
캐릭터 애니메이션이 굳어버리더군요.
혹시 저만 그런건지 확인 부탁드립니다...
안녕하세요!
이 문제를 AnyPortrait v1.4.0에서 해결했으며, 현재 업데이트 가능합니다.
다른 이슈들이 많아서 문제 해결에 많은 시간이 걸린 점 양해 부탁드립니다.
중요한 이슈를 저희에게 알려주셔서 정말 감사합니다!
감사합니다!
안녕하세요!
현재 이슈에 대해서 자세히 검토해주셔서 저희가 문제의 원인을 파악할 수 있었습니다.
감사의 말씀을 먼저 드립니다.
자세한 안내 덕분에, 서로 다른 루트 유닛들에 대한 애니메이션들을 동일 프레임에 동시에 실행 시킬 경우 애니메이션이 동작하지 않는 문제를 저희의 테스트에서도 발견했습니다.
이러한 스크립트 호출 방식은 저희가 전혀 고려하지 못했기 때문에 AnyPortrait의 시스템에서 정상적으로 처리하지 못했습니다.
AnyPortrait의 사양 미비에 의한 버그가 맞습니다.
설명에 앞서서, 이해를 돕기 위해 애니메이션 재생 함수의 과정을 간단히 요약하면 다음과 같습니다.
AnyPortrait는 가능한 모든 처리를 "자신이 업데이트되는 시점"에 하도록 개발되었습니다.
즉, 외부의 스크립트에서 "Play" 함수를 호출했어도, 그 시점에서는 "애니메이션 재생 예약"이 될 뿐이며, 실제로 애니메이션이 재생되지는 않습니다.
그래서 Play 함수를 동시에 여러번 호출해버리면 애니메이션 재생 예약이 중복되어 전달됩니다.
그리고 AnyPortrait의 LateUpdate 루틴에서 이 요청들을 몰아서 한번에 처리합니다.
일반적인 경우엔 "마지막 요청"이 실행되어 문제가 없습니다.
하지만 서로 다른 루트 유닛의 경우엔 이것이 문제가 됩니다.
애니메이션이 재생되고자 할 때, "다른 루트 유닛에 대한 애니메이션"이 있다면 그것을 강제로 중지 시킵니다.
이 과정이 동시에 발생하다보니, 서로 다른 루트 유닛에 대한 재생 요청들은 서로를 강제로 중지시켜버립니다.
이것이 현재 이슈의 원인이었습니다.
이 문제를 해결하기 위해서는 AnyPortrait의 이 시스템을 크게 고쳐야 합니다.
저희도 여러가지 방식으로 이 문제를 현재 버전에서 해결할 수 있는지 검토했습니다.
(애니메이션 데이터 초기화를 강제로 수행하는 시도까지 했습니다.)
하지만 현재 시스템에서는 이 문제를 성급히 해결하려다가 더 큰 문제를 발생시킬 수 있다는 결론을 내렸습니다.
이 이슈는 저희가 다음 업데이트에서 해결하고자 합니다.
하지만 구현 작업에 시간이 많이 걸릴 것으로 예상됩니다.
이점 양해 부탁드립니다.
다소 불편하시더라도, 다음과 같이 스크립트를 작성하셔서 문제를 해결하실 것을 제안합니다.
[이전]
portrait.Play("Motion A");
portrait.Play("Motion B");
portrait.Play("Motion C");
portrait.Play("Motion D");
[제안하는 방식]
string nextAnim = "Motion A";
nextAnim = "Motion B";
nextAnim = "Motion C";
nextAnim = "Motion D";
portrait.Play(nextAnim);
저희가 제안하는 방식은 "이번 프레임에서 재생할 애니메이션"을 string 또는 적절한 타입의 별도의 변수로 저장했다가, 해당 프레임에 단 한번만 Play 함수를 호출하는 방식입니다.
이 방식을 통해서 AnyPortrait 시스템의 문제점을 회피하실 수 있습니다.
사양 미비로 인하여 불편을 드려서 죄송합니다.
이 문제를 핵심 업데이트 과제로 삼고 꼭 해결하겠습니다.
이 이슈에 대하여 더 궁금한 점이 있다면 댓글을 남겨주세요!
감사합니다.
Eng)
This is a bug where animations do not work when animations for different Root Units are played at the same time.
We recommend using a separate variable to avoid the problem.
주말에 덧글을 써주실지 몰랐는데 고생 많으십니다.
3시간 정도 이것저것 실험해가며
글을 열심히 썻는데,
문제점으로 보이는 부분을 발견한것 같아
결국 다 지우고 결론만 말씀드립니다.
다른 루트유닛으로 이루어진 애니메이션을
연속 재생할 시 굳는 현상이 발생하는 것 같습니다.
(이것도 아닐수도 있지만... 지금으로선 가능성이 매우 높다 생각합니다)
우선 해당 애니메이션이 정상 작동하는 모습입니다.
currentAnimeData = portrait.Play("Side_HitDown_Before");
이렇게 한줄로 실행을 하였을 때 입니다.
제가 루트유닛이 3개가 있는데 (Front, Back, Side)
위 Side_HitDown_Before 애니메이션은
Side 루트 유닛으로 이루어진 애니메이션입니다.
(애니메이션의 앞글자가 루트유닛 표시입니다)
하지만 코드를
currentAnimeData = portrait.Play("Front_Hit");
// Front 루트유닛으로 이루어진 애니메이션
currentAnimeData = portrait.Play("Side_HitDown_Before");
// Side 루트유닛으로 이루어진 애니메이션
이런식으로 [다른 루트유닛 애니메이션을 섞어서] 연속 실행시키면
이런 현상이 발생합니다.
캐릭터가 정면을 바라보고 팔도 다리도 머리도 몸통도 움직이지 않는것을 보아
어느 애니메이션도 실행이 안되고 있는 상태입니다.
제 캐릭터가 상하좌우 어디를 바라보고 있어도 같은 현상이 발생합니다.
그런데
currentAnimeData = portrait.Play("Side_Hit"); // Side 루트유닛
currentAnimeData = portrait.Play("Front_Hit"); // Front 루트유닛
currentAnimeData = portrait.Play("Side_HitDown_Before"); // Side 루트유닛
이런식으로 Side 와 Front루트유닛 애니메이션을 한번 실행시켜주고
HitDown 애니메이션을 실행시켜주면
위와 아래를 바라보고 있을 때는(Front, Back 루트유닛 애니메이션)
애니메이션이 정상적으로 작동하고
좌측과 우측을 바라보고 있을 때는(Side 루트유닛 애니메이션)
굳어버리는 현상이 발생합니다.
이것때문에 어떨땐 되고 어떨땐 안되서 정신 나가는줄 알았습니다 ㅠㅠ
currentAnimeData = portrait.Play("Back_FrontOneHandSkillCharge"); // Back
currentAnimeData = portrait.Play("Side_Hit"); // Side
currentAnimeData = portrait.Play("Front_Hit"); // Front
currentAnimeData = portrait.Play("Side_HitDown_Before"); // Side 루트유닛
이런식으로 3방향을 모두 실행시켜주고 본 애니메이션을 실행시켜주면
상하좌우 어디를 바라보고 있는 상태라도 굳어버리는 현상이 다시 발생합니다.
확인 한번 부탁드립니다 b
안녕하세요!
연속적으로 Play 함수를 실행하는 테스트를 해봤습니다만, 문제를 발견할 수 없었습니다.
가장 마지막의 애니메이션이 정상적으로 실행되는 것을 테스트에서 확인했습니다.
저희는 작성하신 전체의 코드를 아는 것이 아니기 때문에 정확한 원인을 알기는 어렵지만, FixedUpdate에 의한 것은 아닌지 조심스럽게 예상해봅니다.
FixedUpdate는 매 프레임마다 실행되는 것이 아니기 때문에, "사용자 입력" 로직을 넣을 수 없으며 Update의 로직과 충돌되기 쉽습니다.
이러한 점에서, 저희는 문의 주신 글에서의 "PlayHitDown" 함수가 아예 실행되지 않았을 수 있다고 생각합니다.
PlayHitDown 함수에 Debug.Log("..") 코드 등을 추가하여 함수가 제대로 실행되는지 확인해보실 것을 권장합니다.
또는 portrait의 Stop()과 같은 함수가 FixedUpdate가 아닌 Update 루틴에서 동시에 실행되면서 애니메이션 실행 요청이 충돌될 수도 있다고 생각합니다.
AnyPortrait 시스템은 FixedUpdate를 고려하지 않기 때문에 스크립트 실행 순서가 올바르지 않았을 수도 있습니다.
애니메이션 실행 문제 뿐만 아니라 조금 더 포괄적으로 스크립트가 정상적으로 실행되는지 확인부탁드립니다.
물론 저희가 생각한 부분이 문제의 원인이 아닐 수 있습니다.
이 글을 바탕으로 다시 검토해보신 후 문제가 해결되지 않는다면 저희에게 다시 알려주세요!
여담으로, 앞의 설명에 덧붙여서, 성능 최적화 등의 이유로 게임의 로직을 FixedUpdate에 작성하는 경우가 있지만, 이것은 많은 문제를 야기시킵니다.
물리 기능과 같이 특수한 경우를 제외하면 가급적이면 매 프레임 호출되는 Update/LateUpdate에 게임 로직을 작성하시는 것을 권장합니다.
만약 고정 FPS를 연출하고자 하는 경우 일지라도, FixedUpdate가 아닌 Update내에서 시간을 계산하여 게임 로직을 동작시키는 것이 여러 문제를 예방시킬 수 있습니다.
Eng)
Q. The problem that the animation does not work when the Play function is called consecutively
A. There was no problem in our test, but the script called from FixedUpdate may be a problem, so please check it.