고도 엔진에서 애니메이션 블렌딩 및 StateMachine 구현 방법 - Whitmem
고도 엔진에서 애니메이션 블렌딩 및 StateMachine 구현 방법
게임 개발 및 엔진
2025-12-20 19:14 게시 c8d17c8298ea1942090a

0
0
5
이 페이지는 외부 공간에 무단 복제할 수 없으며 오직 있는 그대로 게시되며 부정확한 내용을 포함할 수 있습니다. 법률이 허용하는 한 가이드 라인에 맞춰 게시 내용을 인용하거나 출처로 표기할 수 있습니다.
This page is not to be distributed to external services; it is provided as is and may contain inaccuracies.
테스트를 위해서 Blender 에서 임의로 도형을 만들고 움직일 있도록 기본 뼈를 추가합니다.
위 모델은 3개의 동작을 가지고 있으며, Jump, Idle, Forward 세가지 동작을 포함하고 있습니다. 각각 정지 상태에서 Jump, Idle, Forward 세 개의 애니메이션을 수행할 수 있는 키 프레임 집합입니다.
이렇게 추출한 GLB 파일을 고도 엔진으로 불러와서 장면에 드래그하여 넣을 수 있습니다.
이 오브젝트를 장면에 넣은 뒤, 씬 트리 객체에서 우클릭하여 편집할 수 있는 자식을 체크하면 해당 모델 하위에 존재하는 애니메이션 구조가 표시되는 것을 확인할 수 있습니다.
애니메이션 Forward Idle Jump 이 각각 표시되는 것을 확인할 수 있는데, 이를 프로그래밍적으로 직접 재생할 수도 있겠지만, 고도 엔진에서는 애니메이션 재생을 위한 스테이트 머신, 그리고 애니메이션 혼합을 위한 블렌드를 제공합니다.
아무튼 이런 편의 기능을 사용하기 위해서는 AnimationTree를 추가해야 하는데, 장면에 AnimationTree 를 새 노드로 추가합니다.
해당 AnimationTree 의 속성 중 유심히 봐야할 것은 3개의 속성인데, 바로 Tree Root Advance Expression Anim Player 입니다.
TreeRoot 는 이 애니메이션 처리를 도와줄 장치 중 제일 상단에 올 장치를 선택하는 것 입니다. 즉 어떤 메커니즘을 포함하고 있는 하나의 장치라고 보면되며, Tree Root 라는 이름에서 이미 눈치를 챘을 텐데, 필요에 따라 각 노드 하위에 애니메이션 노드를 삽입할 수 있습니다.
다음으로, Advance Expression Base Node 는 우선 지금은 자체 노드로 지정해둡니다. 이 속성은 이 AnimationTree 의 Root Node 하위에 달리는 모든 Expression 식에 대해서 접근할 수 있는 베이스 노드를 의미합니다.
Anim Player 는 이 AnimationTree 에서 상호작용할 AnimationPlayer 객체를 지정합니다. 아까 객체에 포함되어 있던 AnimationPlayer 을 선택합니다.
TreeRoot 는 AnimationNodeStateMachine으로 지정하여 우선 스테이트 머신으로 애니메이션 스위치를 해봅니다.
먼저 스테이트 머신을 생성하면, 아래 루트 스테이트 머신에 대해서 Start End 노드가 존재하는 것을 확인할 수 있습니다.
Start 는 해당 스테이트 머신이 시작하는 진입점, End는 스테이트 머신이 종료되는 끝 점입니다. 즉 Start에서 시작되어 마지막 End로 흘러 들어가는 식입니다. 다만, 이 스테이트 머신은 루트이기 때문에, End 로 마무리되면 더 이상 이 스테이트 머신은 별도의 외부 요청을 하지 않는 이상 영원히 End에서 종료됩니다. 따라서 필요에 따라 스테이트 머신이 종료되면 안된다면 End로 보낼 것이 아니라 다시 진입 점으로 복귀해야 합니다.
Idle 상태
먼저 아무것도 안하고 있을 때 가만히 서 있는 애니메이션을 재생하고자 한다면, 일단 Idle 애니메이션을 재생하고 봅니다.
우클릭 -> 애니메이션 추가-> 기본 상태 애니메이션을 등록하고, Start 노드에서 시프트 클릭을 하여 Idle 쪽으로 당겨주어 이동 경로를 지정해줍니다.
그러면 이 스테이트 머신은 게임 프로젝트가 시작되면 Start에 먼저 진입하고 바로 Idle 애니메이션 모드로 들어갑니다. AnimationTree 노드는 기본적으로 존재하는 TreeRoot 에 대해서 게임이 시작되면 바로 Start 노드로 진입합니다. 따라서 Idle 애니메이션을 재생하고 Idle 애니메이션에서 나갈 끝 점을 지정하지 않는 경우 스테이트 머신은 영구적으로 계속 Idle 상태에 있습니다.
즉 이 상태에서는 Idle 애니메이션이 재생된 후 Idle 노드에 머물러 있는 모습 노란색 테두리을 확인할 수 있습니다. 다만 기본적으로 노드가 한번만 재생되고 멈추는데, 애니메이션 반복을 지정해줌으로써 이 스테이트에 머물러 있을 때 영구적으로 반복 재생 되게 할 수 있습니다.
일회성인 애니메이션을 수동으로 반복하기 위해서 Use Custom Timeline 을 켜고, Timeline Length 에서 애니메이션의 길이(시간), 그리고 Loop Mode를 Linear 등으로 지정하여 반복될 수 있도록 합니다.
그러면 이 애니메이션이 Idle 스테이트에 머물러있는 한 계속 반복되는 것을 확인할 수 있습니다. 이제 이 앞으로 가는 모션을 만들어 보도록 합니다.
먼저 그 전에 앞서, 임의로 AnimationTree 에 공용으로 사용할 플래그 변수를 하나 만들어줍니다. 이 플래그 변수는 현재 플레이어의 상태를 나타내는 UserState 변수입니다. Idle, Forward, Jump 세 가지 중 하나를 선택할 수 있는 공공 공간이라고 보면 됩니다.
이제 스테이트 머신에서 userState 에 따라 스테이트가 이동하도록 구성해 봅니다.
기본적으로 플레이어는 Idle 상태일 때 달리거나, 점프를 할 수 있습니다.
위 Idle 스테이트에서 전이할 수 있는 또 다른 노드는 Forward 또는 Jump입니다.
한편 각 경로를 선택하면 Switch 모드를 지정할 수 있는데 이는 해당 경로가 이전 애니메이션이 어떤 상태일 때 이동될 수 있는지를 나타냅니다.
Immediate 모드인 경우, 이전 스테이트에 도달함과 동시에 바로 이동하는 것을 의미합니다. At End 의 경우 이전 애니메이션이 한번 실행되고 다음 경로로 이동하는 것을 의미합니다. 우선 여기서는 이전 Idle 의 실행이 보장될 필요는 없고, 움직이면 즉시 Forward, Jump 로 스테이트를 이동하기 위해 Immediate 모드로 지정합니다.
위 스테이트 구성에서 Start 를 진행하면 무조건 하나의 스테이트에 고립되는데, 이는 조건을 지정하지 않았기 때문입니다. 여기서 스테이트 머신은 FSM, 즉 유한 상태이고, 하나만 동시에 존재할 수 있기 때문에 무조건 한 개의 경로로만 이동할 수 있습니다. 즉 위 상황에서Idle 스테이트일 때 Forward, Jump 로 이동할 수 있도록 경로를 만들었지만 조건을 별도로 명시하지 않았기 때문에 무조건 하나 이상의 경로로 이동하려는 상황입니다. 따라서 해당 경로에 Forward, Jump 에 맞는 조건식을 넣어줘야 합니다.
따라서 경로 하나를 선택하고, 인스펙터의 Advance를 보면 Condition, Expression 식이 존재하는 것을 확인할 수 있습니다. Condition 도 조건을 넣을 수 있는 공간이지만, 조금 더 다양한 표현과 코드상의 문법들을 사용하기 위해 Expression 공간에 식을 작성합니다. 즉 여기 작성된 Expression 식을 만족하는 경우에만 해당 경로를 타고 다음 상태로 전이될 수 있습니다.
지금 이 AnimationTree 의 C# 스크립트에 UserState 라는 변수를 만들었고, Advance Expression Base Node 를 이 노드로 지정했기 때문에 위 각 스테이트 머신의 Expression 식에서 위 AnimationTree 의 속성에 접근할 수 있습니다. AnimationTree 의 Parameters 내부에 있는 식은 위 Advance Expression Base Node와 별개입니다.
따라서 각 스테이트의 선을 클릭하고 Advance Expression 식에 위 userState 의 조건식을 적어주어 해당 조건이 만족하는 경우에만 스테이트가 전이될 수 있도록 해야 합니다.
하지만, 고도 엔진의 오류 인지는 모르겠으나, C#에서 작성한 Enum 코드는 Expression 식에서 인식하지 못한다는 문제가 (4.3기준) 존재하는 것으로 파악됩니다 (정확하지는 않음), 따라서 비교문에 정수 형태로 넣어줘야 합니다.
이 Enum 번호는 Enum에서 마우스를 가져다 대어 확인할 수 있습니다. 순서대로 0, 1, 2 입니다.
또는 다른 방법으로 직접 메서드를 작성하여 표현식에 메서드를 호출할 수 있습니다.
다만 이 방법을 사용하는 경우 에디터 모드에서는 확인할 수 없고, 프로젝트를 디버깅해야 동작되므로, 스테이트를 실시간으로 확인하기 위해서는 일반적인 수식을 적는 것이 좋아보입니다. 그리고 각 Forward, Jump 에서 다시 Idle로 돌아올 경우의 수도 있기 때문에, 선을 이어줘서 조건식을 작성해줍니다.
각 스테이트에서 Idle로 돌아가는 스테이트 방향에는 UserState 가 Idle 일 때를 Expression 조건으로 구성해줍니다.
그리고 앞으로 가는 도중에 점프를 할 수 있고, 점프하다가 앞으로 갈 수도 있기 때문에 각 경우의 수에 맞는 상태를 만들어줍니다.
이렇게 각 경우의 수를 모두 생각해서 스테이트 머신을 구성해야 고립되는 현상 없이 구현이 가능합니다.
이렇게 구성이 다 되었으면, 이제 최종적으로 AnimationTree 의 UserState 를 직접 변경해봅니다. 변수 값에 따라서 애니메이션이 알아서 잘 동작되는 것을 알 수 있습니다. 즉 별도의 클래스에서 복잡한 연산 없이 에디터에서 제공하는 AnimationTree 와 스테이트를 통해 플레이어의 현재 상태 값에 따라 애니메이션을 알아서 적용할 수 있다는 것이 해당 기능의 장점이라고 볼 수 있습니다. 여기서는 테스트로 UserState 라는 상태 변수를 하나 만들어서 구현했지만, 실제로는 플레이어의 벡터가 일정이상인 경우를 표현식으로 넣어 사용하게 됩니다.
한편, 각 경로에 대해서 인스펙터를 보면 Xfade Time이 존재하는 것을 볼 수 있는데 이는 애니메이션 전환을 할 때 부드럽게 페이드 아웃/페이드 인할 수 있도록 도와줍니다. 즉 애니메이션이 딱딱 끊기며 진행되는 것이 아니라, 부드럽게 보간되어 다음 애니메이션으로 전환되게끔 할 수 있습니다.
댓글 0개
댓글을 작성하는 경우 댓글 처리 방침에 동의하는 것으로 간주됩니다. 댓글을 작성하면 일회용 인증키가 발급되며, 해당 키를 분실하는 경우 댓글을 제거할 수 없습니다. 댓글을 작성하면 사용자 IP가 영구적으로 기록 및 부분 공개됩니다.
확인
Whitmemit 개인 일지 블로그는 개인이 운영하는 정보 공유 공간으로 사용자의 민감한 개인 정보를 직접 요구하거나 요청하지 않습니다. 기본적인 사이트 방문시 처리되는 처리 정보에 대해서는 '사이트 처리 방침'을 참고하십시오. 추가적인 기능의 제공을 위하여 쿠키 정보를 사용하고 있습니다. Whitmemit 에서 처리하는 정보는 식별 용도로 사용되며 기타 글꼴 및 폰트 라이브러리에서 쿠키 정보를 사용할 수 있습니다.
이 자료는 모두 필수 자료로 간주되며, 사이트 이용을 하거나, 탐색하는 경우 동의로 간주합니다.