먼저 움직이고, 과거를 고칩니다
서버의 답이 아직 도착하지 않았는데, 내 캐릭터는 어떻게 바로 움직일까요?
이 글의 목차
내 입력을 먼저 계산하면 조작에 바로 반응할 수 있습니다. 서버의 결과가 도착하면 확인된 과거 상태에서 남은 입력을 다시 실행해 현재를 맞춥니다. 오늘은 이 과정을 숫자와 그림으로 살펴봅니다.
01내 캐릭터는 왜 서버를 기다리지 않을까요?
이동 키를 눌렀는데 캐릭터가 한 박자 늦게 움직이면 답답합니다. 그렇다고 클라이언트가 보내는 위치를 그대로 믿으면, 다른 플레이어와 같은 세계를 유지하기 어렵습니다. 빠른 반응과 서버의 최종 판단을 함께 얻으려면 어떻게 해야 할까요?
오늘은 서버가 이동 결과를 최종 결정하는 서버 권위 구조를 살펴봅니다. 내 컴퓨터를 클라이언트라고 부르겠습니다. 클라이언트가 입력을 보내고 답을 받는 왕복 시간이 120ms라면, 초당 60번 그리는 화면에서는 약 7프레임입니다. 실제 게임에서는 입력 처리와 화면 출력에 걸리는 시간이 더해질 수도 있습니다. 이 수치는 이해를 위한 가정입니다.
해법의 첫 단계는 단순합니다. 내 입력으로 일어날 움직임을 클라이언트에서 먼저 계산하는 것입니다. 이것이 클라이언트 예측(Client-side Prediction)입니다. 서버도 같은 입력을 처리하므로, 나중에 결과가 도착하면 두 계산을 맞출 수 있습니다. Valve의 기술 문서에서 입력을 보관하고 다시 실행하는 기본 구조를 확인할 수 있습니다.

예측한다고 통신 지연이 사라지는 것은 아닙니다. 지연을 기다리는 동안에도 조작에 반응하도록 만드는 것입니다. 그 대신 먼저 계산한 결과가 틀렸을 때 고칠 책임이 생깁니다.
02늦게 받은 좌표를 바로 덮어쓰면 될까요?
캐릭터가 한 줄 위에서 움직인다고 가정해 보겠습니다. 시작 좌표는 10이고, 입력 하나가 좌표를 1씩 늘립니다. 입력에는 순서를 알 수 있도록 번호를 붙입니다.
| 입력 번호 | 클라이언트가 먼저 계산한 좌표 |
|---|---|
| 101 | 11 |
| 102 | 12 |
| 103 | 13 |
이때 서버가 101까지 처리한 좌표는 10.6이라고 알려왔습니다. 충돌 상황 등으로 결과가 달라졌다고 가정한 예제입니다. 현재 좌표 13을 10.6으로 바꾸면 어떻게 될까요? 아직 서버 답이 오지 않은 102와 103의 이동까지 지워집니다.
서버가 보내온 것은 지금의 내 상태가 아니라 입력 101을 처리한 뒤의 상태입니다. 따라서 좌표와 함께 “어디까지 처리했는지”를 알아야 합니다. 서로 다른 시점의 상태를 같은 상태처럼 비교하면 안 됩니다.
올바른 순서는 다음과 같습니다.
- 서버의 101 처리 후 상태인 10.6을 새 기준으로 삼습니다.
- 이미 처리됐다고 확인된 101까지의 입력 기록을 지웁니다.
- 남은 102와 103을 순서대로 다시 실행합니다.
- 10.6 → 11.6 → 12.6이 수정된 현재 예측입니다.

이렇게 서버의 결과를 기준으로 예측을 수정하는 과정을 서버 보정(Server Reconciliation)이라고 부릅니다. 보정된 12.6 역시 모든 입력을 서버가 확인한 최종 결과는 아닙니다. 이후 응답이 오면 다시 맞춰야 할 수도 있습니다.
03무엇을 기록하고 다시 실행해야 할까요?
핵심 흐름을 의사 코드로 적어 보겠습니다. 실제 엔진 API가 아니라 구조를 보여 주는 예제입니다.
입력이 생기면:
입력에 순서 번호를 붙입니다
아직 확인되지 않은 입력 목록에 저장합니다
현재 상태 = Simulate(현재 상태, 입력)
입력을 서버로 보냅니다
서버 상태를 받으면:
현재 상태 = 서버가 확인한 상태
서버가 처리한 번호까지 입력 목록에서 제거합니다
남은 입력을 순서대로 반복합니다:
현재 상태 = Simulate(현재 상태, 입력)
여기서 상태는 위치만을 뜻하지 않습니다. 다음 움직임이 속도, 점프 여부, 바닥에 닿아 있는지에 영향을 받는다면 그 값들도 올바른 시점으로 돌아가야 합니다. 움직이는 발판처럼 관련 물체가 계산에 영향을 준다면, 그 물체를 어떤 시점의 상태로 다룰지도 정해야 합니다.
먼저 작은 이동 모델부터 시작하면 이해하기 쉽습니다. 같은 상태와 입력을 넣었을 때 같은 결과를 얻을 수 있는지 확인해 보세요. 같은 조건에서도 계산 순서나 난수 사용이 달라지면 재실행 결과가 달라질 수 있습니다. 이 성질을 결정론이라고 부릅니다. 모든 물리 시뮬레이션이 자동으로 같은 결과를 보장한다고 가정하면 곤란합니다.
또 하나의 함정은 소리와 효과입니다. 입력 102에서 점프 소리를 냈는데 보정 과정에서 102를 다시 실행하면 소리가 두 번 날 수 있습니다. 이동 계산과 효과 발생을 구분하고, 입력 번호 등으로 이미 실행한 효과를 알아볼 수 있어야 합니다. 잘못 예측한 효과를 취소할지, 짧게 끝나도록 둘지도 게임에 맞춰 정합니다.
계산 상태를 고치는 것과 화면을 자연스럽게 보이게 하는 것도 별개입니다. 이동 계산에는 수정된 상태를 사용하되, 화면에 그리는 위치는 짧은 시간 동안 부드럽게 연결할 수 있습니다. 이 표시 처리를 스무딩이라고 부릅니다.
04되감는다는 말은 언제나 같은 뜻일까요?
네트워크 자료에서 롤백이나 되감기라는 말을 자주 만나게 됩니다. 과거 상태를 사용한다는 공통점이 있지만, 누가 무엇을 위해 되돌리는지는 다릅니다.
| 방식 | 되돌리는 이유와 범위 |
|---|---|
| 내 이동의 예측·보정 | 클라이언트가 서버의 과거 결과에서 내 미확인 입력을 다시 계산합니다. |
| 대전 게임의 롤백 | 늦게 도착한 상대 입력이 예측과 다르면, 저장한 게임 상태에서 다시 진행합니다. |
| 사격 판정의 지연 보상 | 서버가 과거의 대상 상태를 참고해 당시의 명중 여부를 검사합니다. |

오늘의 중심은 첫 번째입니다. 다른 방식까지 한 번에 구현하려 하기보다, 확인된 상태와 남은 입력을 연결하는 과정부터 익혀 보시면 좋겠습니다. 대전 게임 롤백은 GGPO 공식 소개에서 더 살펴볼 수 있습니다.
05엔진에서는 어디를 보면 좋을까요?
Unreal의 Character Movement 문서에는 클라이언트가 이동을 저장하는 구조와 서버 보정 후 다시 적용하는 흐름이 나옵니다. 저장된 이동을 나타내는 FSavedMove_Character, SavedMoves, 보정 후 상태를 갱신하는 ClientUpdatePositionAfterServerUpdate를 찾아보세요. 이름을 외우기보다 입력 기록 → 서버 확인 → 재실행이 어디에 나타나는지 연결하는 것이 목표입니다. 공식 문서의 열람 버전은 UE 5.8입니다.
Unity Netcode for Entities 1.5.1의 예측 문서에서는 PredictedSimulationSystemGroup이 예측 계산을 수행하는 범위를 설명합니다. 한 화면 프레임 안에서도 과거 상태를 따라잡기 위해 여러 번 실행될 수 있습니다. 일반적인 화면 업데이트 횟수와 예측 계산 횟수를 같다고 보면 비용을 놓치기 쉽습니다.
예를 들어 다시 계산할 입력이 6개이고 한 번 계산하는 데 0.2ms가 든다면, 단순 곱은 1.2ms입니다. 실제 비용에는 상태 복원과 기록, 관련 물체의 계산 등이 더해집니다. 이 숫자는 측정 결과가 아니라 생각을 돕는 예시입니다. 지연이 커질수록 반드시 같은 비율로 비용이 늘어나는 것도 아닙니다.
프로파일러에서는 “예측 시스템이 느립니다”보다 조금 더 구체적으로 확인해 보세요.
- 한 번 실행하는 데 얼마나 걸리나요?
- 한 화면 프레임에서 몇 번 실행하나요?
- 지연 조건을 바꾸면 저장 기록과 재실행 횟수는 어떻게 달라지나요?
작은 테스트에서는 입력 번호, 서버가 확인한 번호, 남은 입력 수를 함께 기록하면 보정 흐름을 따라가기 좋습니다. 입력이 두 번 반영되거나 누락될 때 어느 경계가 잘못됐는지 찾기 쉬워집니다.
06오늘 얻어갈 것
처음 질문으로 돌아가 보겠습니다. 서버의 답이 오기 전에 내 입력을 먼저 계산하므로 캐릭터가 바로 반응합니다. 서버의 결과가 도착하면 확인된 과거 상태에서 남은 입력을 다시 실행해 현재를 맞춥니다.
오늘은 세 가지만 기억해 보세요.
- 서버의 상태에는 어디까지 처리했는지를 나타내는 번호가 필요합니다.
- 확인된 입력은 지우고, 아직 확인되지 않은 입력만 순서대로 다시 실행합니다.
- 재실행할 상태와 소리·효과의 중복 처리를 함께 설계해야 합니다.
마지막으로 작은 문제를 풀어볼까요? 클라이언트는 104까지 예측했습니다. 서버는 102까지 처리한 좌표가 11.4라고 알려왔고, 남은 입력은 각각 좌표를 1씩 늘립니다. 어떤 입력을 다시 실행하면 될까요?
답과 이유 보기
103과 104를 다시 실행합니다. 11.4 → 12.4 → 13.4가 수정된 현재 예측입니다. 102까지는 서버 상태에 이미 반영돼 있으므로 다시 적용하지 않습니다. 11.4를 현재 좌표로 그대로 쓰면 103과 104의 이동을 잃게 됩니다.
원문과 더 읽을거리
아래 공개 자료를 바탕으로 구성했습니다. 수치와 그림은 직접 만든 설명용 예제이며 실제 게임의 측정 결과가 아닙니다. 문서 확인일은 2026년 11월 3일입니다.
- Valve / Yahn W. Bernier — Latency Compensating Methods: 입력 보관·재실행과 효과 중복을 설명하는 기술 문서입니다.
- Gaffer On Games — What Every Programmer Needs To Know About Game Networking: 2010년 2월 24일에 작성한 서버 권위와 예측의 배경 설명입니다.
- Unreal Engine — Character Movement: UE 5.8 페이지에서 이동 저장과 보정 흐름을 확인했습니다.
- Unity — Managing latency with prediction: Netcode for Entities 1.5.1의 예측 실행과 비용을 설명합니다.
- GGPO 공식 소개: 입력 예측과 저장 상태를 사용하는 롤백의 출발점입니다.