[무한의 기둥] #02 - 부동 소수점 이야기
작업물이 어느 정도 생길 때마다 개발 일지를 작성하겠다고 했는데
벌써 한 달하고도 2주나 더 지나버렸습니다..
변명 아닌 변명을 해보자면 작업 자체는 꾸준히 진행하고 있었지만,
10월 중순부터 혼자 15일 동안 일본 도쿄 여행을 다녀오느라
잠깐의 강제 휴식기가 있었습니다.
물론 맥북을 챙겨갔기 때문에 틈날 때마다
"여행 중에도 작업을 할 수 있겠지!" 라는 생각을 했으나,
뚜벅이 여행을 많이하는 바람에 15일 중 작업한건 단 2일!
(정말 이곳저곳을 한참동안 걸어서 많이 돌아다녔다)
하지만 현재 개발 일지 내용이 꽤나 밀렸기 때문에..
이번에는 아직 프로토타입 초기 버전 개발이 진행 중이던 시점부텨
가장 최근까지 있었던 이슈들을 몇 가지 이야기해 보려고 합니다.
(저번 첫 편에 다뤄보려고 했으나 내용이 길어지는 것 같아서 제외했었습니다)
부동 소수점 이야기
사실 게임의 핵심인 플레이어가 기둥을 타고 올라가는 기능을
구현하는데까지 별다른 어려움이 없었는데
한 가지 이슈가 있었습니다.
바로 부동 소수점 이슈입니다.
사실 고등학생 시절에 3D 게임 프로젝트를 진행하면서
우연히 이런 현상을 한번 본 적은 있었는데
대부분의 게임은 한정된 공간에서 플레이가 진행되기 때문에
딱히 해결하거나 신경 쓸 이유가 없어서 넘어간 적이 있습니다.
(하지만 이제 해결할 이유가 생겨버렸다)
관련 자료들을 찾아보면 더 자세히 알 수 있겠지만 간단히 요약해보자면
컴퓨터에서 부동 소수점을 표현하기 위한 표준으로는 미터 단위로 1000km 정도가 최대입니다.
(유니티의 Transform Position Y값을 예시로 들면, 어림잡아 1000 정도가 가장 안정적인 수치 값이라고 볼 수 있겠네요)
이렇게 되어있다보니 보통 32비트인 자료형 float을 기준으로 하면 정보 손실없이
그냥 큰 값을 사용하기는 어렵습니다.
(유효 자릿수까지만 잘라내어 저장하므로, 너무 크면 손실이 발생)
처음에 이 현상을 좀 더 확인하기 위해 프로젝트에서 여러 번 테스트를 해보았는데
플레이어의 위치 Y값은 1000 정도가 가장 안정적이었습니다.
(욕심내서 조금만 더 값을 올리면 금방 캐릭터 렌더링이 튀는 현상이 발생)
그리고 이런 문제를 해결한 가장 대표적인 게임이 하나 있는데..
바로 KSP입니다.
우주선 로켓 발사 시뮬레이션 게임인데 Unity 3D 엔진으로 개발했답니다.
(쏘라는 우주선은 안쏘고 미사일[?] 만들어서 쏘고 참 재밌게 했었는데..)
이외에도 유니티로 개발된 다른 우주・시뮬레이션 게임들이 엄청 많을텐데
이 문제를 대체 어떻게 해결했는지 KSP의 대표적인 사례로 확인해봤습니다.
일단 부동 소수점의 정밀도 문제는
물리 엔진과 그래픽 렌더링에서도 큰 영향과 제한을 받습니다.
그리고 좀 더 자료를 찾아보았는데
https://youtu.be/mXTxQko-JH0?t=335
일단 쉽게 요약하자면
1. 우주선을 중심으로 우주 공간 자체를 이동시키는 Floating Origin을 통해
우주선의 위치 값을 최대한 원점에 가깝게 유지시켜서 정밀도를 높임.
2. 이중 정밀도 계산을 위해 별도의 데이터 타입으로 Vector3d와 QuaternionD를 만듬.
3. 물리 연산 단순화 할 수 있도록 함.
저는 이 해결 방식을 꽤나 흥미롭게 보긴 했으나,
현재 프로젝트에는 이 정도의 해결법이 필요하진 않을 것 같다는 생각이 들었습니다.
일단 우주 높이까지 올라갈 수 있겠지만,
설계상 유저들이 쉽게 도달할 수 있는 점수의 한계치가 정해져 있고
그렇다고 해당 높이까지 올라가서 다른 상호작용을 하는 것은 아니기에
저 해결법을 참고하여 구현하는건 너무 불필요할 정도로 과한 방식이라 판단을 내렸습니다.
그래서 가장 간단하고 쉬운 방법으로 해결하기로 했는데 바로 "적당히 눈속임을 하자!" 였습니다.(잠깐.. 동작 그만 밑장빼기냐?)눈속임? 뭘 어떻게?
간단합니다.
일단 2D뷰로 인게임 씬을 살펴보면
기본적으로 지상의 땅과 산 오브젝트를 제외하고는 그냥 스카이박스 배경이 있는게 전부입니다.
게임의 진행을 생각해 보면 땅에서 멀어질수록 땅과 가까운 오브젝트들과 거리가 멀어지면서 점점 보이지 않게 됩니다.
그러면 플레이어가 기둥을 타고 올라가다가
카메라에서 지상의 오브젝트들이 완전히 보이지 않게 되었을때,
그리고 부동 소수점 이슈가 발생하지 않는 적정한 값 범위의 높이에 도달하는 순간!
해당 위치에서 플레이어 캐릭터의 높이를 계속 유지하되, 올라가는 것처럼 보이게 하면 됩니다.
(배경의 높이를 점점 내려가게하는 선택지도 있었으나, 조금만 생각해보니 올바른 선택지는 아니다 판단)
하지만 해당 방식을 적용해서 해결하려면 추가로 함께 수정해야할 부분들이 생겼었습니다.
1. 원래라면 실제 위치 변동에 따라 플레이어를 따라와야 하는 카메라의 팔로우 처리
2. 한계 높이에 도달하면 기둥의 높이 고정 처리
3. 고정된 높이에서 캐릭터의 좌우 이동 처리
크게 어려운 부분은 아니였으나
좀 신경써야하는 부분은 카메라의 팔로우 처리였습니다.
이 부분은 실제로 위치 변동에 따라 올라갔을때와
최대한 비슷한 움직임을 주고 싶었기 때문에
최대한 티나지 않게 카메라 위치에 일정 값을 더해서
페이크 이동 처리를 별도로 구현했습니다.
(움짤로는 너무 티가 안 나서 첨부하지 않는 걸로)
이렇게 부동 소수점 이슈는 일단 해결했으나
이것말고도 앞으로 해결해야할 이슈가 더 생겼었습니다..
일본어 폰트 대응
변수 및 리더보드 보안 이슈
등등..
일지를 작성하는 현재에는 이미 대부분 해결한 상황이지만
마지막으로 하나만 더 이야기해보도록 하겠습니다.
일본어 폰트 대응
프로젝트 초기에는 한국어와 영어 문자 정도만 문제 없이 출력될 수 있는 폰트를 적용했었는데,
일본어나 중국어 정도는 추가로 지원해도 괜찮겠다는 생각이 들었습니다.
일단 일본어만 추가로 로컬라이징 작업을 진행하고자 했는데
바로 여기서 문제가 발생했습니다.
폰트 중에 특정 문자가 지원되지 않아 텍스트가 제대로 출력되지 않거나,
해당 문자 부분만 대체 폰트로 바뀌어 출력되는 바람에 한 문장의 텍스트에
여러 폰트가 혼합되어 어울리지 않게 되었습니다..
예상했던 문제이긴한데, 폰트 자체에서 문자가 호환되지 않는다는건
사전에 미리 판단하지 못한 저의 미스였습니다.
(한글이 유독 잘 어울리는 폰트였는데)
차마 이대로 버리고 아예 기본 타겟 폰트를 바꿀 수는 없었고,
마침 현재 프로젝트에서는 TMP (TextMeshPro)를 사용하고 있었기 때문에
기본 타겟 폰트와 유사한 대체 폰트를 찾아서 추가로 대응하기로 했습니다.
기본 타겟 폰트에서 지원되지 않는 영문 문자도 있기 때문에
아예 한국어, 영어, 일본어로 나눠서
폰트를 불러오지 못하는 경우
(Fallback 발생 시)
바로 다음 대체 폰트로 받아와서
그냥 통째로 적용될 수 있도록 해주었습니다.
(Font Atlas 생성도 Dynamic으로 적용하여 아예 폰트 자체에서 지원될 수 있는 것들만 적용)
이외에도 위에서 언급한 보안 이슈, 방해 이벤트 추가 등
작업한 사항들이 몇 가지 더 있었는데 빠른 시일내로
다음 편에서 이야기 해볼 수 있도록 해보겠습니다.