온라인 게임에서 타이밍 맞추기
누군가와 온라인으로 "같이" 플레이한다는 건 생각보다 복잡하다. 겉으로 보기에는 그냥 서로 인터넷에 연결되어 있으니 데이터를 주고받으면 끝일 것 같지만, 실제로는 전혀 그렇지 않다. 이걸 어렵게 만드는 건 여러 가지가 있지만, 그중에서도 제일 큰 건 결국 타이밍 문제다.
보통은 내가 보낸 데이터가 상대방에게 바로 도착한다고 생각하기 쉽다. 거의 즉시 전달되는 것처럼 느껴지니까. 그런데 실제로는 "즉시"가 아니라 "즉시에 가깝게" 도착할 뿐이다.
당연한 말이지만 데이터도 공간을 건너가야 한다. 그리고 그 속도에는 한계가 있다. 아무리 빨라도 빛의 속도를 넘을 수 없고, 우리가 실제로 쓰는 광섬유나 네트워크 장비는 그보다 더 느리다. 게다가 경로도 직선이 아니다.
지도에서 보면 서울에서 뉴욕까지 대략 11,000km 정도인데, 이런 거리에서는 왕복 지연이 금방 사람이 체감할 만한 수준이 된다. 현실에서는 광섬유 내부 속도, 경로 우회, 중간 장비를 다 거치니까 200ms를 넘는 경우도 전혀 이상하지 않다. 타자를 빠르게 치는 사람이면 그 시간 동안 두 글자 정도는 써버릴 수 있다.
그럼 서울에서 서울이면 괜찮을까? 물론 훨씬 낫다. 그래도 "같은 도시니까 거의 0에 가깝겠지"는 아니다. 일반적인 인터넷 경로를 타면 통신사 내부를 돌고 여러 장비를 거치면서 보통 수십 ms는 그냥 나온다. 대충 30ms에서 50ms 정도는 흔하다. 반대로 AWS 같은 같은 리전 안에서 서버끼리 묶어 두면 한 자릿수 ms까지 내려가기도 한다. 이 차이가 꽤 크다. 결국 온라인 게임에서는 내가 보고 있는 상대 상태가 "지금 이 순간"이 아니라, 수십 ms 전 상태라는 걸 전제로 짜야 한다.
내가 선택한 방법은 기준 시간을 하나 잡는 방식이었다. 게임 시작 시간을 공통 기준으로 두고, 각 클라이언트에서 이벤트가 발생한 시각을 같이 기록한다. 내가 무언가를 선택했으면 내 클라이언트에서 그 시간을 찍고, 상대도 자기 클라이언트에서 발생한 시간을 기록한다. 그리고 상대에게서 넘어온 이벤트를 도착한 순서 그대로만 처리하지 않고, 그 이벤트가 실제로 발생한 시간 기준으로 내 이벤트들 사이에 끼워 넣는다.
이렇게 하면 네트워크 지연이 있어도 화면상 싱크를 훨씬 자연스럽게 맞출 수 있다. 물론 완벽하진 않다. 가끔은 내가 먼저 본 이벤트보다 상대 이벤트가 실제로는 더 먼저였는데, 전송이 늦어서 나중에 도착하는 경우가 있다.
내가 만든 게임에서는 이게 치명적인 문제는 아니었다. 아주 정밀하게 판정을 맞춰야 하는 장르도 아니고, 그런 경우의 빈도도 높지 않았다. 그래서 로직 전체를 무겁게 만들기보다는, 보여지는 부분에서만 약간의 예외 처리를 넣는 쪽을 선택했다. 이정도로도 충분히 유저들끼리 '같이 하고 있다'는 느낌을 줄 수 있었다. 실제로는 수십 ms 전의 상대방과 같이 하고 있음에도 불구하고.
전체 글