폰 브라우저에서 박자 맞추기, 리듬 게임 6종의 판정 엔진
랜선포차의 369·딸기·바니바니·공산당·007빵·두부 게임이 함께 쓰는 박자 판정 엔진. 빠름 250ms·늦음 350ms 창을 정한 근거, 다음 박에 잘못 붙던 입력, 폰 화면에서 박자를 보여 주는 방식을 적었다.

랜선포차의 미니게임 24종 중 여섯 개는 박자 게임이다. 369, 딸기 게임, 바니바니, 공산당 게임, 007빵, 두부 게임. 모임에서 손뼉 치며 하던 게임을 폰 화면으로 옮기면, 결국 “이 사람이 박자에 맞게 눌렀나”를 누군가 판정해야 한다. 여섯 게임이 제각각 판정하면 게임마다 억울함의 종류가 달라진다. 그래서 판정은 엔진 하나로 모았다.
9월 27일 새벽에 여섯 게임과 공용 판정 엔진, 테스트 45개를 한 커밋(92995ff)으로 올렸다. 그리고 한 시간도 안 돼서 판정이 틀렸다는 걸 알았다. 이 글은 그 엔진의 구조와, 고친 부분에 대한 기록이다.
박자표는 서버가 공개하고, 판정도 서버가 한다
엔진의 기본 생각은 이렇다.
- 서버가 박자표를 정해서 모두에게 공개한다. 박자표는 “박 0의 서버 시각, 처음 박 간격, 몇 박마다 얼마나 빨라지는지, 가장 빠른 간격” 네 가지다.
- 클라이언트는 서버 시계에 맞춘 시계로 같은 함수를 돌려서 메트로놈 소리와 박자 막대를 그린다.
- 입력은 “몇 번째 박에 대한 입력인지”를 달고 올라간다. 판정은 서버가 받은 시각 기준이다.
서버 시계 보정은 단순하다. 클라이언트가 주기적으로 핑을 보내고, 지금까지 왕복 시간이 가장 짧았던 응답으로 서버와 내 시계의 차이를 잡는다. 왕복이 짧을수록 오차가 작기 때문이다.
게임마다 다른 것은 템포와 “그 박에 누가 무엇을 해야 하는가”뿐이다. 엔진은 박 k가 오기 0.5초 전에 게임에게 “박 k에 필요한 동작”을 물어보고, 그 시점에 확정한다. 지목 게임은 앞 박에서 누가 누구를 찍었는지가 반영된 뒤에 다음 할 일이 정해져야 하기 때문이다.
| 게임 | 처음 박 간격 | 빨라지는 방식 | 가장 빠를 때 |
|---|---|---|---|
| 369 | 900ms | 6박마다 −30ms | 600ms |
| 딸기 게임 | 750ms | 8박마다 −25ms | 500ms |
| 바니바니 | 800ms | 8박마다 −30ms | 560ms |
| 공산당 게임 | 520ms | 9박마다 −20ms | 450ms |
| 007빵 | 1,100ms | 5박마다 −40ms | 800ms |
| 두부 게임 | 700ms | 6박마다 −20ms | 480ms |
공산당 게임의 하한 450ms에는 사연이 있다. 지목을 받은 사람은 다음 “당!“까지 세 박 안에 누구를 찍을지 골라야 한다. 450ms × 3이면 약 1.35초인데, 이보다 짧으면 사람이 화면을 보고 고를 시간이 사라진다. 그래서 규칙 파일에 “450ms 아래로는 안 내린다”는 주석과 함께 하한을 박아 두었다.
빠름 250ms, 늦음 350ms
판정 창은 박 시각을 기준으로 앞으로 250ms, 뒤로 350ms다. 비대칭으로 잡은 이유를 규칙 파일 주석에 그대로 남겨 두었다.
| 항목 | 값 | 근거 |
|---|---|---|
| 빠름 허용 | 250ms | 사람은 메트로놈에 맞출 때 박을 50 |
| 늦음 허용 | 350ms | 안드로이드 WebAudio 출력 지연 50 |
| 놓침 판정 여유 | 40ms | 늦음 창이 닫힌 뒤 타이머 오차 흡수 |
| 연타 박 | 두 번째부터 +220ms씩 | 369의 33처럼 박수를 여러 번 쳐야 하는 박 |
| 카운트인 | 4박 + 준비 0.9초 | 하나·둘·셋·넷 |
폰에서 소리를 듣고 누르면 모든 지연이 “늦게” 쪽으로 쌓인다. 소리가 늦게 나오고, 손가락이 화면에 닿는 것이 늦게 인식되고, 그 입력이 서버에 늦게 도착한다. 대칭 창(예: ±300ms)을 쓰면 제대로 누른 사람이 “늦음”으로 지는 일이 잦아진다. 그래서 늦은 쪽을 100ms 더 열었다.
같은 이유로 타일을 누르는 이벤트도 바꿨다. 지목은 다른 사람의 화상 칸을 누르는 동작인데, click은 손가락을 뗄 때 발생한다. 이를 누르는 순간 발생하는 pointerdown으로 바꾼 커밋(bdb81c2)의 메시지에는 “지목 입력 50~100ms 빨라짐”이라고 적혀 있다.
다음 박에 붙어 버리던 입력
첫 버전은 입력을 “가장 가까운 박”에 붙였다. 느린 템포에서는 문제가 없다. 그런데 박 간격이 늦음 창의 두 배(700ms)보다 짧아지면 이상한 일이 생긴다. 박 5에 맞춰 300ms 늦게 누른 입력이, 박 간격이 500ms라면 박 6까지 200ms밖에 안 남았으니 박 6에 더 가깝다. 그러면 박 5는 “놓침”이 되고, 박 6에는 할 일이 없는데 눌렀으니 또 실수가 된다. 분명 제때 눌렀는데 진다.
고친 방식은 “내 할 일이 남은 박을 먼저 본다”이다. 입력 시각 주변의 박들 중 아직 내가 눌러야 하는 박이면서 −250ms~+350ms 안에 드는 가장 이른 박을 먼저 고르고, 그런 박이 없을 때만 가장 가까운 박에 붙인다. 클라이언트와 서버가 같은 함수를 쓰고, 서버는 한 번 더 확인해서 다음 박에 잘못 붙어 온 입력을 직전 박으로 옮긴다. 이 수정이 들어간 커밋(a9506fb)의 제목 앞부분은 “리듬 게임 품질 수정: 박자 오판정(늦은 입력이 다음 박에 붙던 문제, 클라·서버)“이다.
바니바니에서 “귀”를 늦게 누른 판정. 빠름·늦음·놓침은 게임마다 다른 병맛 문구로 바뀌어 뜬다.
끝까지 아무도 안 틀리면, 가장 들쭉날쭉한 사람
리듬 게임은 누가 틀리면 그 자리에서 끝난다. 그런데 마지막 박까지 아무도 안 틀리면 벌칙 받을 사람이 없다. 이때는 박자가 가장 들쭉날쭉했던 사람이 “공인 박치”로 진다.
여기서 “들쭉날쭉”을 평균 오차로 재면 불공평하다. 네트워크가 느린 사람은 모든 입력이 일정하게 늦게 도착하기 때문이다. 그래서 오차의 표준편차를 쓴다. 매번 80ms씩 늦게 도착하는 사람은 표준편차가 0에 가깝고, 한 번은 이르고 한 번은 늦는 사람이 박치가 된다. 일정한 지연은 상쇄되고 흔들림만 남는다. 반대로 표준편차가 가장 작은 사람(두 번 이상 누른 사람 중)은 라운드 1등이 된다.
폰 화면이 박자를 보여 주는 방식
판정은 서버가 하지만, 박자를 느끼는 건 폰 화면과 소리다. 여섯 게임은 박자 막대와 메트로놈을 한 파일에서 같이 쓴다.
| 요소 | 동작 |
|---|---|
| 화면 시계 | 매 프레임 서버 보정 시계를 다시 읽음 |
| 카운트인 | “하나·둘·셋·넷”을 막대에 크게 띄우고, 이 네 박은 강한 소리 |
| 메트로놈 | 박마다 틱 소리. 늦게 화면을 열어 이미 120ms 넘게 지난 박이면 소리를 건너뜀 |
| 누른 직후 | 내 폰 기준 ±90ms 안이면 “딱 좋아!”, 밖이면 “빠름”이나 “느림”을 0.45초 동안 표시 |
| 진동 | 누를 때마다 25ms |
| 누가 걸리면 | 그 박 0.4초 뒤에서 화면 시각을 멈추고 걸린 사람과 사유를 배너로 표시 |
화면 시계를 매 프레임 읽는 이유는 단순하다. 다른 화면처럼 100ms마다 시각을 갱신하면, 박자 막대의 반짝임이 최대 100ms씩 늦게 켜진다. 판정 창이 250ms인 게임에서 100ms 어긋난 눈금은 쓸 수 없다.
“딱 좋아!“와 “빠름·느림”은 판정이 아니라 안내다. 내 폰의 시계로 계산한 오차라서, 서버가 받은 시각과는 조금 다를 수 있다. 그래도 누른 직후 바로 보여 주면 “내가 박보다 앞서 누르는 버릇이 있구나”를 한두 박 만에 알 수 있다. 서버 판정을 기다렸다가 보여 주면 이미 다음 박이 지나가 있다.
누가 걸렸을 때 화면을 멈추는 것도 같은 이유다. 박자 막대가 계속 굴러가면 누가 왜 졌는지 볼 새가 없다. 막대를 멈추고 “○○ — 늦음” 같은 배너와 게임별 병맛 한 줄을 띄운 뒤에야 다음 장면으로 넘어간다.
개발 중 자동 시뮬레이션으로 여섯 게임을 300판씩 돌렸을 때 모두 100% 정상 종료했고, 한 판 중앙값은 16.5초(바니바니)에서 26.3초(369) 사이였다. 박자 게임은 한 판이 짧아서, 틀린 사람이 나와도 금방 다음 라운드로 넘어간다.
정리
엔진은 결국 “억울하게 지지 않게”를 수치로 옮긴 것이다. 늦게 쏠리는 폰의 지연을 창 모양에 반영하고, 빠른 템포에서 입력이 엉뚱한 박에 붙지 않게 하고, 일정한 지연은 박치 판정에서 지웠다. 화면은 판정을 대신하지 않고, 내가 얼마나 어긋났는지만 바로 알려 준다.
게임별 규칙과 요령은 공산당 게임, 007빵, 두부 게임 공략에 따로 정리했다. 직접 박자를 맞춰 보고 싶다면 랜선포차 게임 페이지에서 한 판 해 보면 된다.


