유니티에서 애니메이션 왜 행동 상태를 관리하는 방법 - Whitmem
유니티에서 애니메이션 왜 행동 상태를 관리하는 방법
게임 개발 및 엔진
2026-01-01 22:21 게시 092e8d4770bba2036b7f

0
0
2
이 페이지는 외부 공간에 무단 복제할 수 없으며 오직 있는 그대로 게시되며 부정확한 내용을 포함할 수 있습니다. 법률이 허용하는 한 가이드 라인에 맞춰 게시 내용을 인용하거나 출처로 표기할 수 있습니다.
This page is not to be distributed to external services; it is provided as is and may contain inaccuracies.
이번에 유니티 엔진을 통해 애니메이션을 구현해 보았고, 이제 각 캐릭터 상태를 구현하는 방법에 대해 공부를 해 보았다. 단순히 캐릭터 하나의 컴포넌트에 대해서 움직임을 모두 구현하는 것이 아니라, 각 움직이는 조건 및 상태를 각각의 상태로 분할해서 스테이트에서 비로소 관리하게 되는 것을 알게 되었다.
즉 스테이트 머신은 하나의 스테이트를 가질 수 있고, 현재 객체의 update, render 등을 현재 활성된 하나의 스테이트에 계속 요청을 보내어, 해당하는 스테이트만 처리를 수행할 수 있도록 돕는다. (마치 현재 선택된 장면을 렌더링하는 처리와 유사하다.) 그리고 각 스테이트에는 Enter, Exit가 존재하는데, StateMachine 에서 ChangeState 될 때 이전 스테이트에는 Exit를 호출하고, 새로운 스테이트에는 Enter을 호출함으로써 각 스테이트 상태를 독립적으로 수월하게 관리할 수 있는 듯 싶다.
무엇보다 각 스테이트에서 발생할 수 있는 상황만 구현함으로써 달리는 도중에만 공격할 수 있는 스킬 등은 Walk라는 스테이트에서만 구현하면 되는 것이다. 물론 이것은 상황에 따라 메인에서 조건부로 모두 작성하고 스테이트만 동기화되도록 하거나 하는 등 고민이 필요하겠지만 아무튼 애니메이션을 적용하기 위해서는 스테이트로 관리하는 것이 편리해 보였다. 애니메이션도 유한 상태 머신으로 동작되기 때문에, 상태를 유한 상태 머신으로 동작해두면, 각 행동 상태 머신에 활성화된 상태에서 독립적으로 애니메이션을 요청하면 되기 때문이다.
다만, StateMachine을 굳이 만들고 PlayerStateMachine 에서 다시 상속하는 이유, State를 만들고 PlayerState 에서 다시 상속하는 이유는 Player 측에서만 구현 가능한 기타 사항들이 있을 수 있기 때문이다. 나중에 동물, 기타 잡다한 오브젝트에도 상태를 적용할 수 있기 때문에 확장 가능성을 고려해서 가능성을 남겨둔다.
스테이트는 각 상태마다 필요할 것으로 보이는, 콜백으로 호출되어야 하는 기타 메서드들을 구현한다.
스테이트 머신에서는 하나의 스테이트를 활성화된 스테이트로 가질 수 있고, 변경할 수 있고, 각 request를 요청하는 것을 목적으로 한다. changeState 시 해제되는 (제거되는 것이 아니다) 스테이트는 exit를, 새로운 스테이트는 enter을 요청한다.
PlayerState는 State 를 상속하는데, 여기서 비로소 애니메이션 이름을 하나 지정하면 내부적으로 해시를 만들어 보관하고, 플레이어 스테이트 머신과 관계를 지어 참조할 수 있게끔 구현하였다. 여기서 애니메이터도 가져와 내부적으로 애니메이터 클래스에 접근할 수 있게끔 하였다. 즉 각 스테이트 하나 하나가 독립적으로 해당 상태에 관련된 애니메이션만 재생할 수 있도록 트리거를 요청하거나 변수를 제어해야하므로 Animator에 접근할 수 있는 접근자를 남겨두어야 한다. 각 스테이트 마다 일일이 애니메이터를 직접 코드로 참조할 수는 없기 때문에 StateMachine으로 부터 참조받아 가져오는 식으로 구현하는 것이다. 그리고 필요에 따라 각 상태 하나는 여러개의 애니메이션 해시를 필요로할 수 있다. 여기서 상태는 애니메이션 상태가 아니라 행동 상태이다. 행동 상태는 애니메이션과 100% 동일하지 않을 수 있기 때문에, 여기서는 연습 삼아서 하나의 애니메이션만을 해시로 보관하지만 필요에 따라서는 List로 관리하거나 따로 로직을 구현할 필요가 있다.
이제 예를 들어 IdlePlayerState 를 구현하는데, 이 상태 스테이트는 진입할 때 애니메이션은 Idle 이라는 명칭의 애니메이션을 재생해야하므로 Idle을 부모에 보낸다. 그리고 스테이트 enter시에 getAnimator을 통해서 getAnimationHash() 즉 위 부모에서 처리된 애니메이션의 이름 hash를 가져와 해당 애니메이션이 재생될 수 있도록 트리거를 동작한다. 그리고 update에는 해당 스테이트가 활성화 상태일 때 각 프레임마다 실행되어야 할 추가 동작들을 명시할 수 있다. 여기서 키보드 입력 등을 받을지, 이벤트를 받을지는 개발자의 마음인 듯 하다. 다만 성능 누수가 발생하지 않도록 이벤트를 등록하는 등 남발하는 행위는 위험해 보인다. 나의 경우는 애초 스테이트를 하나 가지는 스테이트 머신쪽에(PlayerStateMachine) 하나의 데이터를 Attach(참조)할 수 있도록 해두었고 getAttachment라는 메서드를 만들어 캐릭터 객체를 가져와 캐릭터 객체에서 상태 메서드(isIdle, isRun) 등을 가져와 단순히 행동만 전이 시켜주는 코드를 update()에 구현했다. 실질적으로 키보드 입력 등의 동작은 모두 캐릭터 무브먼트라는 클래스 하나에서 처리된다.
이 때 다른 스테이트로 전이하기 위해서 다른 스테이트의 클래스 인스턴스를 가져와야하는데 각 스테이트마다 새로운 인스턴스를 만드는 것이 아니다. PlayerStateMachine 이라는 관리 머신에 public getter 로 각 인스턴스를 미리 만들어두고 가져올 수 있게끔 해야 한다.
별개로 Trigger의 경우 가끔씩 상황에 따라 무시되는 상황이 있을 수 있으므로 변수나 속도 제어 값 등으로 구현하는 것이 좋아보인다.
댓글 0개
댓글을 작성하는 경우 댓글 처리 방침에 동의하는 것으로 간주됩니다. 댓글을 작성하면 일회용 인증키가 발급되며, 해당 키를 분실하는 경우 댓글을 제거할 수 없습니다. 댓글을 작성하면 사용자 IP가 영구적으로 기록 및 부분 공개됩니다.
확인
Whitmemit 개인 일지 블로그는 개인이 운영하는 정보 공유 공간으로 사용자의 민감한 개인 정보를 직접 요구하거나 요청하지 않습니다. 기본적인 사이트 방문시 처리되는 처리 정보에 대해서는 '사이트 처리 방침'을 참고하십시오. 추가적인 기능의 제공을 위하여 쿠키 정보를 사용하고 있습니다. Whitmemit 에서 처리하는 정보는 식별 용도로 사용되며 기타 글꼴 및 폰트 라이브러리에서 쿠키 정보를 사용할 수 있습니다.
이 자료는 모두 필수 자료로 간주되며, 사이트 이용을 하거나, 탐색하는 경우 동의로 간주합니다.