네트워크 환경에서 플레이어의 조작 반응성을 최적화하기 위해 예측(Prediction) 및 재조정(Reconciliation) 시스템을 설계하고 구현했습니다.
단순히 서버의 응답을 기다리는 방식이 아닌, 클라이언트에서 결과를 선제적으로 예측하고 서버의 권한을 유지하면서 오차를 보정하는 방식을 채택하여, 핑이 높은 환경에서도 이질감 없는 조작감을 제공합니다.
| 방식 | 설명 | 장점 | 단점 |
|---|---|---|---|
| Stop & Wait | 서버 응답 후 이동 | 구현 단순함, 완벽한 동기화 | 입력 지연 발생, 유저 경험 저하 |
| Teleport | 선 이동 후 오차 시 텔레포트 | 즉각적인 반응 | 핑이 높을 시 심한 끊김과 떨림 발생 |
| Prediction & Reconciliation | 선 이동 후 과거 시점 재현 | 최고의 반응성 및 부드러움 | 구현 복도 높음, 결정적 시뮬레이션 필요 |
초기에는 엔진 내장 물리 시스템을 사용했으나, 특정 객체(플레이어)만을 과거 시점으로 되돌려 부분적 재시뮬레이션을 수행하는 데 한계가 있었습니다.
이를 해결 하기 위해 개요의 Telport방식에 선형 보간을 섞어 이용했으나 100ms 이상의 핑에서 고무줄 현상이 크게 발생하여 foothold기반 예측-재조정 움직임 시스템을 개발하게 됐습니다.
[엔진의 물리엔진을 사용한 기존의 지형 시스템 | 선 기반 foothold 시스템]
[teleport 기반 | prediction-reconciliation 기반]
핑 1000ms 기준 teleport기반 방식은 반응이 느려지는 것을 볼 수 있습니다.(모션은 나오지만 이동을 못함)
예측 및 재조정 방식으로 바꾼 후로 해당 현상은 사라졌습니다.
- 서버와 클라이언트 간의 상태 불일치를 최소화하기 위해 모든 이동 로직은 FixedUpdate 기반의 고정 프레임워크에서 실행됩니다. 이는 프레임 드랍 등 클라이언트 환경 변화와 무관하게 일관된 물리 연산 결과를 보장합니다.
- 상태 기록: 틱(Tick)마다 현재의 요청 번호, 위치, 속도, 입력값을 버퍼에 저장합니다.
- 입력 감지 및 전송: 입력 상태가 변경될 경우에만 서버에 패킷을 전송하여 네트워크 대역폭을 최적화합니다.
- 예측 수행: 서버의 응답을 기다리지 않고 로컬에서 즉시 물리 연산을 수행하여 캐릭터를 이동시킵니다.
- 재조정: 서버로부터 상태 패킷이 도착하면, 해당 시점의 로컬 기록과 서버 데이터를 비교합니다.
- 임계치 이상의 오차 발생 시 서버가 확정한 과거 시점으로 위치를 되돌린 후, 버퍼에 쌓인 미확인 입력값들을 순차적으로 다시 적용하여 현재 위치를 결정합니다.
- 입력 검증: 클라이언트로부터 받은 입력 패킷을 검증하고, 새 입력이 오기 전까지 마지막 입력을 유지하며 FixedUpdate에서 시뮬레이션을 진행합니다.
- 특정 주기마다 플레이어에게 상태 패킷을 전송합니다.
- 서버는 클라이언트의 틱 정보를 바탕으로, 해당 이동이 완료된 시점의 클라이언트 틱을 계산하여 응답에 포함합니다. 이는 클라이언트의 재조정에 사용됩니다.
패킷을 보낸 시점의 클라이언트 틱 + (현재 서버 틱 - 패킷을 받은 시점의 서버 틱);
- 서버는 클라이언트의 틱 정보를 바탕으로, 해당 이동이 완료된 시점의 클라이언트 틱을 계산하여 응답에 포함합니다. 이는 클라이언트의 재조정에 사용됩니다.
Note
클라이언트로부터 받은 입력은 즉시 처리하는 것이 아니라, 클라와 서버의 틱 차이를 계산하고 서버는 그 차이만큼 늦게 처리합니다. 그렇게 하지 않으면 아주 짧은 입력의 경우 키를 뗄 때까지 클라이언트는 3틱만큼 물리 연산을 했지만, 서버는 5틱만큼 처리하는 경우가 생겨 예측에 오차가 발생합니다.

