파이널 프로젝트 4주차다.
우리팀은 에셋을 뒤늦게 정했는데 기존 작업을 조금 빠르게 끝마치고 할거 없어진 내가 캐릭터 애니메이션을 맡게되었다.우리팀이 구매한 캐릭터에셋 제너레이터의 사용은 굉장히 간단했다.
첨부된 씬을 킨뒤에 원하는대로 커스터마이징하고 저장버튼을 누르면 프리팹의 형태로 저장이 되는 구조."오 할거없겠는데?"
라면서 안일하게 생각했던 나였지만 에셋을 까보고 경악을 금할수 없었다.
1. Spine
Spine은 스켈레톤 애니메이션을 만드는 유니티 외부툴중 하나이다.
자연스러운 움직임을 만들수있지만 당연히 그만큼 리소스를 많이 잡아먹으며,
대규모 N vs N 전투가 이뤄지는 우리게임에선 그만큼의 자연스러운 애니메이션은 필요하지 않았다.
2. PartsManager
가장 큰 문제였다.
구매한 에셋제너레이터를통해 캐릭터를 생성하면 기본캐릭터로 프리팹이 생성되고
거기엔 PartsManager 스크립트와 CharacterPrefabData 스크립트가 붙어있었다.
그리고 게임을 실행하면 CharacterPrefabData가 PartsManager를 통해 사용자가 커스터마이징한 데이터를 가져와 조립하는 형식이었다.
애니메이션은 생각보다 부담이 적었지만 생성될때마다 프레임이 뚝뚝 끊기며 FPS는 10까지도 내려가는 상황.
아직 풀링이 적용되지않아 최적화의 여지는 많았지만 스킬, 이펙트등 추가적인 작업이 많이 필요한 상황에서
대공사가 필요함은 자명한 사실이었다.
튜터님께도 조언을 구하니 "애니메이션 스프라이트를 미리 베이킹해라" 라는 답변을 받았다.
여기저기 방법을 찾아봤다.
제작자에게 원본 Spine을 받아 Spine to Sprite를 하는법 등등 여러가지 해결책이 있었지만
결국 PartsManager의 존재때문에 커스터마이징 기능을 활용하려면 커스터마이징 및 애니메이션 코드를 싹 새로짜지않는 이상
단순한 전처리로는 해결을 할 수 없었다.
그래서 내가 내린 결론은 캐릭터를 프레임별로 스프라이트로 만들자 라는것이었다.
일단 빠르게 실현가능여부를 확인해보았다.
캐릭터 애니메이션을 프레임별로 캡쳐해서 스프라이트로 저장하는건 30분만에 구현이 완료되었다.
물론 CS지식이 부족해서 렌더텍스쳐에 대한 디테일한 공부는 구현후 추가로 진행했지만 기능 구현자체는 금방이었다.
사실 이대로도 스프라이트가 존재하는 이상 애니메이션을 지닌 프리팹을 만들기만 하면 되는것이라 이단계에서도 문제해결은 끝난것과 다름이 없었다.
하지만 최소 14개 캐릭터의 최소 4가지의 모션, 스프라이트는 최소 4프레임으로만 잡아도 최소 200번 이상의 반복 노가다 작업...
그걸 할 자신은 없었다.
그래서 나는 애니메이션을 담은 프리팹을 추출하는 파이프라인 자체를 구축하기로 마음먹었다.
Sprite, AnimationClip, AnimatorController, 곧바로 사용가능한 유닛 Prefab이 생성된다.구현은 그렇게 복잡하지 않았다.
런타임상에서 실제로 실행될 코드가 아니기때문에 최적화를 신경쓰지 않아도 되며
어차피 개발 초기, 혹은 추후 컨텐츠 추가때만 사용될 재사용성이 낮은 코드이기때문에 확장성도 크게 고려하지않았다.
애초에 Sprite를 저장하는것까지 구현이 이미 완료된 상태였기때문에
그걸 애니메이션 클립으로 만들고, 필요한 애니메이션만큼 반복생성한뒤, 애니메이션 컨트롤러를 만들고, 그걸 프리팹으로 만든다.
이런 직관적인 데이터의 흐름이 있었기때문이었다.
나머지는 유니티가 제공해주는 자체 API를 적극적으로 활용하기만 하면 될뿐.
그렇게 나머지 기능도 모두 완성이 되었다.
여기에 추가적으로 아래 기능까지 구현을 완료했다.
Player Unit을 생성할지, EnemyUnit을 생성할지 선택할수있는 토글기능작업 착수부터 완성까지 대략 반나절 조금 넘게 소요된것 같다.

왼쪽은 샘플캐릭터, 오른쪽은 내가 추출을 원하는 캐릭터이다. 여기서 원하는 애니메이션을 좌상단에서 매핑하고 PlayerUnit여부만 선택을 해준뒤 RecordStart버튼을 누르면...



자동으로 완성된 애니메이션, 스프라이트, 프리팹이 완성된다!
코드는 굉장히 지저분하고 비효율적이며 에러 발생확률도 굉장히 크고 552줄이라는 폭력적인 길이를 지니고 있지만 뭐 어떠한가.
유저가 사용할 기능도 아닌데.
내부 소스코드에서 사용한 유니티 API나 구현중 겪었던 이슈 등 기타 디테일하게 적고 싶은 내용도 많지만 그건 내용이 너무 길어질것 같아 그건 후편으로 미루도록 해야할것 같다.
딱히 자조적인 의미는 아니지만 나는 평범한 개발자이기도하고, 또한 내가 흥미를 갖는것이 대부분 수학적 계산이 불필요한 부분들이기에 지금까지 개발을 하면서 이건 너무나도 구현 난이도가 높다! 라고 느낀 경험은 솔직히 없다.
사실 이건 대부분의 개발자가 비슷하지 않을까한다.
결국 대부분의 얼마만큼의 시간이 걸리고 얼마나 좋은 방법을 찾느냐의 차이일뿐이지 결국 모두가 구현은 해낸다.
특히 이는 AI시대에 접어들면서 더더욱 그러하다고 생각한다.
그렇다면 결국 중요한것은 구현을 해내느냐 이전에 어디까지, 그리고 어떤식으로 결과물을 낼것인지 판단하는 능력이 아닐까한다.
만약 내가 이 파이프라인을 구축할 생각을 하지 않았다면 나는 캐릭터에셋을 잘못구매한 과거의 우리팀을 원망하며 하나하나 스크린샷을 찍고 이미지를 조정하며 애니메이션을 만드는 작업을 하고 있었을지도 모른다.
그렇기에 고수들에겐 어찌보면 보잘것 없는 구현일수도 있지만 이번 경험은 개인적으로 가장 인상깊은 트러블슈팅 경험중 하나가 될것 같다.