멀티플레이 동기화가 깨질 때 부동소수점 vs 고정소수점

profile_image
작성자 네트워크게임개발자 하람
댓글 0건 조회 4회

같은 입력을 전달했는데도 10분 뒤 두 클라이언트의 캐릭터 위치가 달라진다면, 네트워크보다 먼저 수치 연산을 의심해야 합니다. 특히 락스텝 방식의 멀티플레이 게임에서는 작은 반올림 오차가 충돌 판정과 무작위 수 소비 순서를 바꾸고, 결국 전혀 다른 게임 상태를 만들 수 있습니다.

이때 개발팀이 마주하는 선택은 선명합니다. 익숙하고 빠른 부동소수점 연산을 통제해 결정론을 확보할 것인가, 아니면 표현 범위와 개발 편의성을 양보하고 고정소수점 연산으로 이동할 것인가입니다. 두 방식의 승자는 장르, 플랫폼, 동기화 범위에 따라 달라집니다.

재현되지 않는 오차가 멀티플레이를 무너뜨리는 순간

한 프레임의 차이가 전투 결과를 바꾼다

싱글플레이에서 0.0001만큼 어긋난 위치는 대부분 눈에 띄지 않습니다. 하지만 모든 참여자가 동일한 입력으로 같은 상태를 계산해야 하는 락스텝 구조에서는 이야기가 달라집니다. 한 기기에서 공격 범위 안으로 판정된 유닛이 다른 기기에서는 범위 밖으로 판정되면, 피해량뿐 아니라 다음 목표 선정과 경로 탐색 결과까지 갈라집니다.

부동소수점은 넓은 범위와 높은 정밀도를 효율적으로 표현하지만, 연산 순서와 컴파일러 최적화, CPU 명령어 집합에 영향을 받을 수 있습니다. 예를 들어 여러 힘을 합산할 때 왼쪽부터 더한 결과와 크기순으로 더한 결과가 미세하게 다를 수 있습니다. 그 값이 임계 조건문을 통과하는 순간, 단순한 수치 차이는 게임 규칙의 분기 차이로 확대됩니다.

문제의 핵심은 오차의 크기가 아니라 오차가 게임 로직에 연결되는 방식입니다. 화면에만 쓰이는 파티클 위치는 달라도 괜찮지만, 명중 판정이나 자원 생산량, 난수 시드에 영향을 주는 값은 반드시 같아야 합니다. 먼저 다음 항목 중 어디까지 동기화 대상인지 구분해야 합니다.

  • 반드시 동일해야 하는 값: 유닛 위치, 체력, 충돌 결과, 스킬 발동 틱, 게임플레이 난수 상태
  • 차이를 허용할 수 있는 값: 카메라 흔들림, 이펙트 입자, 오디오 피치, 장식용 애니메이션 보간
  • 경계에 있는 값: 물리 기반 투사체, 루트 모션, 시야 판정, 내비게이션 비용
동기화 버그를 찾을 때는 화면이 처음 달라진 프레임이 아니라, 두 상태 해시가 처음 달라진 틱을 찾아야 합니다. 시각적 이상은 원인보다 수십 프레임 늦게 나타나는 경우가 많습니다.

부동소수점은 개발 속도와 생태계에서 앞선다

기존 엔진 기능을 그대로 활용하는 선택

부동소수점 방식의 가장 큰 장점은 게임 엔진과 개발 도구가 이미 이를 중심으로 설계되어 있다는 점입니다. 벡터, 행렬, 쿼터니언, 물리 엔진, 애니메이션, 셰이더 입력까지 거의 모든 계층이 float 사용을 전제로 합니다. 프로토타입을 빠르게 만들거나 서버가 최종 상태를 판정하는 구조라면 이 생태계를 포기할 이유가 적습니다.

현대 CPU의 SIMD 명령과 GPU 연산도 부동소수점 처리에 매우 유리합니다. 고정소수점보다 항상 빠르다고 단정할 수는 없지만, 범용 엔진에서 복잡한 수학 함수를 사용한다면 최적화된 라이브러리를 활용하는 편이 대체로 경제적입니다. 특히 역제곱근, 삼각함수, 행렬 분해가 빈번한 3D 게임에서는 직접 만든 정수 기반 구현의 검증 비용이 급격히 커집니다.

다만 ‘모든 플랫폼에서 float가 있으니 결과도 같을 것’이라는 가정은 위험합니다. 컴파일 옵션이 연산 재배치를 허용하는지, 융합 곱셈-덧셈이 사용되는지, 비정규 수를 0으로 처리하는지 확인해야 합니다. 부동소수점을 선택한다면 다음 통제 장치를 개발 비용에 포함해야 합니다.

  • 결정론 영역에서 빠른 수학 최적화 옵션을 끄고 빌드 설정을 고정합니다.
  • 플랫폼마다 다른 수학 함수 대신 검증된 공통 구현을 사용합니다.
  • 컨테이너 순회 순서와 병렬 작업 완료 순서가 합산 결과를 바꾸지 않게 합니다.
  • 거리 비교에서는 제곱근을 피하고, 가능한 경우 정수화한 임계값을 사용합니다.
  • 게임 상태를 일정 주기로 해시해 크로스 플랫폼 리플레이 테스트를 실행합니다.

부동소수점이 충분한 게임

서버 권위형 액션 게임처럼 서버가 정답을 보유하고 클라이언트가 예측 결과를 보정하는 구조에서는 완전한 결정론보다 보정의 품질이 중요할 수 있습니다. 협동 게임에서 소수의 오브젝트만 동기화하거나, 리플레이가 입력 재생이 아니라 상태 스냅샷 기반이라면 float를 유지하는 편이 구현 난도를 크게 낮춥니다.

고정소수점은 같은 입력에 같은 답을 강제한다

정수 위에 소수 표현을 얹는 방식

고정소수점은 정수의 일부 비트를 소수부로 해석합니다. 예를 들어 32비트 값에서 16비트를 정수부, 16비트를 소수부로 사용하면 내부 값 65536이 실제 수 1을 뜻합니다. 덧셈과 뺄셈은 정수 연산처럼 처리하고, 곱셈과 나눗셈에서는 비트 이동과 더 넓은 중간 자료형을 사용해 소수점 위치를 보정합니다.

동일한 비트 폭과 오버플로 규칙을 유지하면 플랫폼이 달라도 같은 입력에서 같은 결과를 얻기 쉽습니다. 이는 대규모 RTS, 대전 격투, 결정론적 리플레이처럼 수천 번의 시뮬레이션을 정확히 재현해야 하는 게임에 강력한 이점입니다. 상태 전체를 자주 전송하지 않고 입력만 공유할 수 있으므로 네트워크 대역폭도 절약할 수 있습니다.

대신 표현 범위와 정밀도가 고정되어 있다는 대가가 따릅니다. 월드 좌표가 커질수록 소수부 비트를 줄여야 하고, 작은 값을 정밀하게 표현할수록 큰 값을 담기 어려워집니다. 곱셈 중간값이 자료형 범위를 넘는 오버플로도 조용히 잘못된 결과를 만들 수 있어, 자료형 설계 단계부터 실제 게임 단위를 계산해야 합니다.

  1. 최대 월드 크기와 원점에서의 최대 거리를 정합니다.
  2. 필요한 최소 이동 단위와 충돌 허용 오차를 결정합니다.
  3. 속도·가속도·시간을 곱했을 때 발생하는 최대 중간값을 계산합니다.
  4. 곱셈에는 64비트 또는 128비트 중간 자료형이 필요한지 확인합니다.
  5. 포화 연산, 예외 처리, 래핑 중 어떤 오버플로 정책을 쓸지 명시합니다.
고정소수점의 비트 배치는 수학 라이브러리만의 결정이 아닙니다. 레벨 크기와 캐릭터 속도, 무기 사거리까지 함께 보는 게임 디자인 계약에 가깝습니다.

라이브러리 비용을 과소평가하면 안 된다

기본 사칙연산만 구현하면 끝날 것처럼 보이지만 실제 게임에는 정규화, 각도 변환, 삼각함수, 보간, 제곱근이 필요합니다. 각각의 근사 알고리즘은 정확도와 속도 사이에서 선택해야 하며, 오차 범위를 테스트로 고정해야 합니다. 기획 역할과 수치 요구사항의 관계를 설명할 때는 기획자에 관한 지식백과 설명도 팀 내 역할 합의에 참고할 수 있습니다.

성능 대결은 자료형보다 시뮬레이션 구조가 좌우한다

정수 연산이면 무조건 빠르다는 착각

고정소수점은 정수 연산을 사용하므로 빠르다는 설명이 자주 등장하지만, 실제 성능은 그렇게 단순하지 않습니다. 부동소수점 곱셈은 현대 CPU에서 매우 빠르게 처리되는 반면, 고정소수점 나눗셈이나 포화 처리, 넓은 중간값 변환은 추가 명령을 요구합니다. 벡터화가 잘된 float 코드와 분기가 많은 고정소수점 코드를 비교하면 전자가 앞설 수도 있습니다.

반대로 결정론을 위해 단순한 충돌 모델과 제한된 수학 함수만 사용하는 RTS 시뮬레이션에서는 고정소수점이 예측 가능한 성능을 제공합니다. 이 경우 진짜 이득은 개별 덧셈의 속도가 아니라 데이터 크기, 캐시 적중률, 재현 가능한 병렬화에서 나옵니다. 같은 자료형을 택해도 배열 중심으로 연속 배치한 코드는 포인터가 흩어진 객체 구조보다 훨씬 안정적인 프레임 시간을 보입니다.

비교할 때는 초당 연산 수만 재지 말고 실제 게임 틱 전체를 측정해야 합니다. 테스트 맵에는 평상시 유닛 수뿐 아니라 최악의 밀집 전투, 대량 생성과 제거, 경로 갱신이 겹치는 상황을 넣어야 합니다. 개발자 행사에서 공개되는 최적화 사례를 탐색할 때 GDC의 성격과 배경을 먼저 살펴보면 발표 자료의 맥락을 이해하기 좋습니다.

  • 측정 범위: 물리, AI, 경로 탐색, 상태 해시를 포함한 한 틱 전체
  • 입력 규모: 평균 상황과 상위 1% 최악 상황을 각각 기록
  • 플랫폼: 개발용 PC뿐 아니라 최소 사양 CPU와 실제 서버 환경 포함
  • 관찰 지표: 평균 시간, 95·99백분위 시간, 캐시 미스, 할당 횟수
  • 검증 조건: 최적화 빌드에서도 결과 해시가 일치하는지 확인

먼저 작은 수직 단면을 비교한다

전체 엔진을 고정소수점으로 바꾸기 전에 이동, 회전, 원형 충돌, 단순 투사체가 포함된 수직 단면을 두 방식으로 구현해 보십시오. 구현 시간과 실행 시간뿐 아니라 디버깅 난도, 테스트 코드 분량, 디자이너가 값을 조정하는 데 걸리는 시간까지 기록해야 선택의 실제 비용이 드러납니다.

혼합형 설계는 타협이 아니라 경계 설정이다

게임 규칙과 표현 계층을 분리한다

두 방식 중 하나를 엔진 전체에 강제할 필요는 없습니다. 게임 결과를 결정하는 시뮬레이션 코어는 고정소수점으로 작성하고, 렌더링과 카메라, 애니메이션은 부동소수점으로 유지하는 혼합형 구조가 실용적입니다. 핵심은 두 세계 사이의 변환이 언제, 어느 방향으로 일어나는지 명확히 제한하는 것입니다.

예를 들어 시뮬레이션은 초당 30틱으로 고정소수점 위치를 계산하고, 렌더링 계층은 직전 틱과 현재 틱의 값을 float로 변환해 보간할 수 있습니다. 사용자가 보는 움직임은 부드럽지만 명중 판정은 렌더링 좌표가 아니라 확정된 시뮬레이션 좌표를 사용합니다. 애니메이션 발자국 위치나 카메라 보간값이 게임 상태로 역류하지 않게 단방향 데이터 흐름을 유지해야 합니다.

이 구조에서는 API 이름도 경계를 드러내야 합니다. FixedVector를 암묵적으로 Vector3로 변환하게 만들면 편리하지만, 어느 순간 float 결과가 시뮬레이션으로 되돌아갈 가능성이 커집니다. 변환 함수에 명시적인 이름을 붙이고 코드 리뷰 규칙이나 정적 분석으로 금지된 의존성을 확인하는 편이 안전합니다.

영역권장 표현이유
이동·충돌·피해 판정고정소수점게임 결과 재현이 필요함
카메라·파티클·화면 흔들림부동소수점시각 품질과 도구 호환성이 중요함
UI 수치 표시확정 상태에서 변환표시값이 규칙 계산에 역류하지 않음
GPU 셰이더 입력부동소수점그래픽 파이프라인과 직접 호환됨
리플레이 검증 해시원본 정수 비트변환 과정의 차이를 제거함

예산은 초기 구현비보다 유지비로 본다

고정소수점 라이브러리 제작비만 계산하고 장기 유지비를 빼면 판단이 왜곡됩니다. 신규 개발자의 학습 시간, 디버거 표시 도구, 에디터 프로퍼티 입력, 플랫폼별 테스트 장비, 수학 함수 확장 비용까지 포함해야 합니다. 기능별 비용과 효과를 연결하는 관점은 계획예산 제도의 개념처럼 목표와 자원 배분을 함께 보는 데 도움이 됩니다.

  • 시뮬레이션 어셈블리에서 엔진 물리 API 직접 호출을 금지합니다.
  • 에디터에는 실제 값과 내부 정수 값을 함께 표시합니다.
  • float 변환은 렌더 스냅샷 생성 단계에서 한 번만 수행합니다.
  • 네트워크 패킷에는 스케일 규칙과 자료형 버전을 명시합니다.

경쟁 게임과 소규모 협동 게임의 선택은 달라야 한다

리플레이와 관전까지 제품 기능인 팀

입력만 저장해 장시간 경기를 정확히 재생해야 하고, 여러 운영체제와 CPU에서 동일한 판정을 보장해야 하는 경쟁 게임 팀이라면 고정소수점 중심의 결정론적 코어가 유리합니다. 대규모 RTS나 입력 지연에 민감한 격투 게임처럼 잦은 전체 상태 전송이 부담스러운 장르도 같은 선택에 가까워집니다.

다만 곧바로 엔진 전체를 교체하지는 마십시오. 먼저 이동과 판정에 필요한 수치 범위를 문서화하고, 10만 틱 이상의 입력 재생 테스트를 구축해야 합니다. 그다음 최소 사양 장치 두 종류와 서버 환경에서 상태 해시를 대조하십시오. 이 검증을 통과하지 못한다면 자료형을 바꿔도 결정론을 확보했다고 말할 수 없습니다.

  • 고정된 틱과 난수 생성 순서를 시스템 계약으로 관리합니다.
  • 오버플로와 0 나눗셈은 빌드 유형별 처리 정책을 명시합니다.
  • 매 틱 핵심 상태 해시를 남기고 최초 불일치 지점을 자동 추출합니다.
  • 리플레이 파일에 게임 규칙 버전과 수학 라이브러리 버전을 기록합니다.

빠른 콘텐츠 제작과 엔진 활용이 중요한 팀

반면 2~4명이 만드는 소규모 협동 게임이고 서버가 권위 있는 결과를 보내며, 물리 엔진과 애니메이션 도구 활용이 개발 속도를 좌우한다면 부동소수점을 유지하는 편이 낫습니다. 완전한 크로스 플랫폼 결정론을 위해 수개월을 쓰기보다 입력 예측, 스냅샷 보간, 위치 보정이 자연스럽게 보이도록 다듬는 것이 사용자 경험에 더 직접적인 영향을 줍니다.

당신의 게임이 ‘한 경기의 모든 순간을 입력만으로 다시 계산해야 하는가’에 예라고 답한다면 고정소수점 쪽으로 이동하십시오. 반대로 ‘서버 상태를 주기적으로 받을 수 있고 엔진 물리와 제작 도구가 핵심 자산인가’에 예라고 답한다면 부동소수점을 통제하는 전략이 적합합니다. 두 독자에게 필요한 것은 같은 자료형이 아니라, 게임 결과를 책임지는 수치와 화면 표현용 수치의 경계를 끝까지 지키는 설계입니다.

  1. 소규모 협동 게임 개발자는 float 빌드 설정을 통일하고 상태 보정 품질부터 측정합니다.
  2. 경쟁형 결정론 게임 개발자는 고정소수점 수직 단면과 장시간 리플레이 검증부터 시작합니다.
  3. 두 경우 모두 첫 상태 불일치 틱을 자동으로 찾는 도구를 개발 일정에 포함합니다.
댓글목록

등록된 댓글이 없습니다.