서론

진행하고 있는 프로젝트에서, 간단히 유저들 끼리 서로 캐릭터들의 위치(움직임) 이나 상태 등을 실시간으로 확인해야 하는 기능이 있어, 난생 처음으로 게임 서버 비슷한 무언가를 구현 해보았다.

우선 처음에는 굉장히 안일하게 생각했었다.

플레이어가 느낄 때 부드러워 보이려면 1초에 60번의 화면을 새로 그려내야 한다. (60프레임)

따라서 각각의 클라이언트가 1초에 60번씩 자신의 위치를 서버로 전송하고, 서버에서 1초에 60번씩 모든 클라이언트들 에게 모든 클라이언트의 위치를 담은 정보를 전송하면 되지 않을까? 라는 생각을 하였다.

하지만 아주 소수만 사용하는 서비스면 몰라도, 1초에 60번이나 n 명의 클라이언트들 에게 n 명의 데이터가 담긴 전체 데이터를 전송하려고 하면 엄청난 서버 부하를 일으킬 것이다.

해서 보통 1초에 10회 내외로 클라이언트 ↔︎ 서버 간의 통신이 이루어 진다고 한다. (저빈도 업데이트)

그렇다면 각각의 클라이언트들은 1초에 60회를 그려내야 캐릭터의 움직임이 자연스럽다고 느끼는데, 1초 동안 60개의 위치 데이터가 필요할 텐데, 겨우 10개의 데이터를 가지고 어떻게 스무스하게 캐릭터의 움직임을 표현할 수 있을까? 라는 의문이 생긴다. 그 의문을 추측 항법을 이용하여 해결해 보았다.

실행 화면

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/3c4278b8-7a40-4396-9310-d7ad2fd9581e/멀티플레이_동기화.mov

위 시뮬레이션을 보면 좌 / 우 화면이 약간의 딜레이를 두고 서로의 움직임을 그려낸다. 이것이 추측항법의 열쇠이다.

→ 각각의 클라이언트는 자신의 상태(현재 위치한 좌표) 를 1초에 10번 서버로 보낸다.

→ 서버는 모든 클라이언트의 상태(현재 위치한 좌표) 를 1초에 10번 broadcast 한다.

→ 클라이언트는 1초에 60회(모니터 프레임) 화면을 다시 그려낸다.

클라이언트 동작 순서

  1. 접속하면 서버와 100회의 핑을 주고받아 서버의 시간과 클라이언트 머신의 시간(javascript 에서는 Date.now()) 을 동기화 한다.
  2. 이후 서버로부터 1초에 10회 다른 모든 클라이언트들의 움직임을 담은 정보를 수신하고, 또한 1초에 10회 자기 캐릭터의 위치를 담은 정보를 서버로 송신한다.
  3. 매 초마다 60회씩 자신을 포함한 모든 클라이언트들의 움직임을 그려낸다. 이 때, 추측항법을 사용하여 비어있는 시간은 가장 가까운 타임스템프가 찍힌 두 점을 이은 곳으로 진행한다.