시행착오

애니메이션 이벤트 + DOTween 회전 실행 오류 // 02/21 수정(Root Motion)

Cadi 2025. 2. 20. 22:07

잘 실행되던 애니메이션이, 애니메이션 이벤트로 하니까 실행되지 않는 오류가 있었다. 

 

public class QuizCardPositionStateFlip : QuizCardPositionState, IQuizCardPositionState
{
    public QuizCardPositionStateFlip(QuizCardController quizCardController) : base(quizCardController) { }
    
    public void Trasition(bool withAnimation, Action onComplete = null)
    {
        var animationDuration = (withAnimation) ? 5f : 0f;
        var animator = _quizCardController.GetComponentInParent<Animator>();
        _rectTransform.DORotate(new Vector3(0, 90, 0), animationDuration / 2)
            .OnComplete(() =>
            {
        _rectTransform.DORotate(new Vector3(0, 0, 0), animationDuration / 2)
                    .OnComplete(() => onComplete?.Invoke());
            });
    }
}

 

다음과 같은 함수가 실행되서 DORotate로 회전하는 함수였다.

매개변수도 올바르게 받았고, animationDuration도 내가 원하는대로 설정되었고, 심지어는 OnComplete도 올바르게 실행되었다. 

 

일단 이 함수가 실행되는 과정을 보자. 

 

public void OnClickOptionButton(int buttonIndex)
{
    // Timer 일시 정시
    timer.PauseTimer();
    
    if (buttonIndex == _answer)
    {
        Debug.Log("정답!");
        // TODO: 정답 연출
        // SetQuizCardPanelActive(QuizCardPanelType.CorrectBackPanel);
        ShowQuizCardResult(QuizCardResultType.Correct);
    }
    else
    {
        Debug.Log("오답~");
        // TODO: 오답 연출
        // SetQuizCardPanelActive(QuizCardPanelType.InCorrectBackPanel);
        ShowQuizCardResult(QuizCardResultType.Incorrect);
    }
}

 

버튼을 누르면 ShowQuizCardResult 함수가 호출된다.

private void ShowQuizCardResult(QuizCardResultType quizCardResultType)
{
    switch (quizCardResultType)
    {
        case QuizCardResultType.Correct:
            quizCardResultPanel.SetActive(true);
            _animator.SetTrigger("correct");
            break;
        case QuizCardResultType.Incorrect:
            quizCardResultPanel.SetActive(true);
            _animator.SetTrigger("incorrect");
            break;
        case QuizCardResultType.None:
            quizCardResultPanel.SetActive(false);
            break;
    }
}

 

 

애니메이터가 SetTrigger되고 다음과 같은 애니메이션이 실행된다. 

 

public void SetQuizCardPanelActive(int TypeOrder)
{
    QuizCardPanelType quizCardPanelType;
    if (TypeOrder == 1) quizCardPanelType = QuizCardPanelType.CorrectBackPanel;
    else quizCardPanelType = QuizCardPanelType.InCorrectBackPanel;
    ShowQuizCardResult(QuizCardResultType.None);
    SetQuizCardPanelActive(quizCardPanelType, true);
}

 

여기서 타입을 받아와서 실행한다. 

SetQuizCardPanelActive로 보내면서 애니메이션도 재생하라고 보낸다. 

 

만일 알맞은 옵션 버튼을 클릭했다면 

case QuizCardPanelType.CorrectBackPanel:
    frontPanel.SetActive(false);
    incorrectBackPanel.SetActive(false);
    
    _positionStateContext.SetState(_positionStateFlip, withAnimation, () =>
    {
        correctBackPanel.SetActive(true);
        correctBackPanel.GetComponent<RectTransform>().anchoredPosition = Vector2.zero;
        incorrectBackPanel.GetComponent<RectTransform>().anchoredPosition = _incorrectBackPanelPosition;
    });
    break;

 

이게 실행된다. 

 

public void SetState(IQuizCardPositionState state, bool withAnimation, Action onComplete = null)
{
    if (_currentState == state) return;
    
    _currentState = state;
    _currentState.Trasition(withAnimation, onComplete);
}

 

여기서 우리가 처음에 봤던 기능이 실행되는 것이다.

 

 

처음에는 무언가 잘못되어서 중간 동작에 오류가 있는줄 알았다.

그래서 중단점을 찍어가며 봤지만, 말했던 것처럼 올바르게 진행되었다. 

 

 

중간에 이런 말씀이 있으셔서, enum 타입으로 선언해서 넣어주었던 것을 바꿔보기도 했다.

 

public void SetQuizCardPanelActive(QuizCardPanelType quizCardPanelType)
{
    // QuizCardPanelType quizCardPanelType;
    // if (TypeOrder == 1) quizCardPanelType = QuizCardPanelType.CorrectBackPanel;
    // else quizCardPanelType = QuizCardPanelType.InCorrectBackPanel;
    ShowQuizCardResult(QuizCardResultType.None);
    SetQuizCardPanelActive(quizCardPanelType, true);
}

/// 친 부분이 바꿨던 부분이다. 

 

그래도 안되서 계속해서 로그도 찍어보고 인스펙터도 들여다 봤다.

 

 

 

한 한 시간즈음 헤매고 인스펙터 창에서 단서를 찾았다. 

인스펙터 창에서 퀴즈 카드의 로테이션이 회전하지 않고 있었다.

SetState 함수가 호출되었을 때 Top값과 Bottom값이 올바르게 동작하지만, Rotation만 안되었다. 

 

현재 애니메이터가 꺼지지 않았고 ,아이들 상태에서 현재 Rotation을 유지하려는 상태가 지속되어서 

내가 DORotate로 돌려주려고 했을 때에도 기본 상태를 유지했던 것이다. 

사실 아직 왜 위아래로는 움직이고 회전은 안되는지는 잘 모르겠어서 GPT강사님에게 물어봤다. 

 

이걸 애니메이터 설명에 써놨어야지 유니티 이자식아 !!!

두 시간은 고생했네 ; 

 

밑의 내용으로 수정했다 !

 


02. 21 수정

 

어제 아무리 생각해도 이해가 가지 않았다. 아침에 강사님께서 다른 방법도 설명해 주셨는데 바로 

Apply root motion 이다. 

 

Apply root motion은 애니메이션의 움직임 데이터로 게임 오브젝트의 Transform을 직접 제어하는 기능이다. 

일반적으로, 애니메이션은 게임오브젝트의 Transform을 직접 움직이지 않고, 시각적인 표현만 해 준다. 

루트 모션 기능을 이용해서 직접적으로 이동 및 회전 정보를 조작할 수 있다.

True(체크) : 애니메이션에 포함된 Root Motion 데이터를 사용해 Transform 을 직접 제어 / 애니메이션이 실제로 움직임

False(언체크) : 애니메이션이 시각적으로 움직임만 표현, Transform에 영향을 미치지 않음

 

저게 언체크 되어 있었기 때문에, 애니메이션 상태에서 실제 Transform은 움직이지 않고 시각적인 표현만 된다.

이 상태에서 애니메이션이 끝나면 원래 상태인 idle 상태로 돌아가게 되는데 이 때문에 문제가 발생하게 된다.

우리는 이 상태에서 DORotate를 사용해 회전값을 변경하려고 했다. 

그런데 다시 보면 애니메이션 클립의 제어 항목 중에 Rotation이 있다.

그렇기 때문에 이 클립이 끝나고 돌아간 후 idle 상태에서도 이 회전값을 지키려는 성질이 남아 있어 

이후에 DORotate로 회전값을 조정해 주려 하였어도 제대로 되지 않는 것이었다.

그리고 이 애니메이션 클립에는 위 아래RectTransform 값 조정은 들어가 있지 않아서 위 아래로 움직이는

DOAnchorPos나, 투명값을 조정해주는 DOFade는 올바르게 작동하는 것이다.

 

혹시 몰라서 실험을 통해 애니메이션 클립에 RectTransform중 Top, Bottom 값을 Add Key 해 추가해 본 후

다시 실행해 봤을 때, 원래 잘 작동되던 위아래로 움직이던 애니메이션도 실행이 되지 않는 것을 볼 수 있다. 

이는 GPT에게 물어봤을 때 답해준 애니메이터가 기본적으로 회전값을 더 강하게 제어하는 것이 아니라,

Root Motion을 체크 해제하고 idle 상태에 들어갔을 때, 전에 제어하던 Transform 값 등을 유지하려는 성질이 있기 때문이다.

이젠 GPT 강사님을 신뢰하지 못하겠다..