commits

다리 건너기 베팅 게임을 멀티플레이어로 이식했다

R
이더
2026. 04. 27. AM 09:55 · 6 min read · 0

🤖 5330 in / 2000 out / 7330 total tokens

다리 건너기(bridge-cross)를 목업에서 실제 베팅형 멀티플레이어 게임으로 이식했다. 61개 파일, +4228줄. LAMDiceBot의 4번째 게임으로 들어간다. 기존 주사위/룰렛/경마와 동일한 베팅 구조를 따른다.

게임 룰은 단순하다. 6색 캐릭터(빨주노초파남)가 유리 다리를 건넌다. 각 행에 안전한 유리와 깨지는 유리가 있다. 플레이어는 "누가 N번째 시도에 통과하나"에 베팅한다. 서버가 시나리오를 결정하고, 클라이언트는 결정론적으로 재생만 한다. 클라이언트가 Math.random을 쓰지 않는 게 핵심이다. 모든 탭이 동일한 결과를 보여야 하니까.

서버 핸들러는 socket/bridge-cross.js에 378줄로 들어갔다. 경마 핸들러(socket/horse.js) 패턴을 그대로 차용했다. 베팅/시작/결과 세 phase로 나뉘고, K(통과 순서), safeRows(각 행의 안전 열), scenarios(전체 시나리오)를 서버에서 생성해서 클라이언트에 내려준다. 상수값도 조정 가능하게 분리해뒀다 — BRIDGE_COLUMNS=6, BRIDGE_BETTING_SEC=15, BRIDGE_MIN_PLAYERS=2 등.

socket/rooms.js에는 bridge-cross를 게임 타입 화이트리스트에 추가하고, leaveRoomuserColorBets를 정리하는 로직을 넣었다. 이걸 빼먹으면 나간 유저의 베팅이 방에 잔류해서 메모리 누수 + 로직 버그가 발생한다. utils/room-helpers.jscreateRoomGameState()에도 bridgeCross 초기 상태를 추가했다. phase, bettingDeadline, safeRows, scenarios, 타이머 참조까지 전부 초기화.

클라이언트 bridge-cross-multiplayer.html은 2583줄짜리 단일 HTML이다. 표준 수직 스택 레이아웃 — 접속자, 준비, 베팅, 주문, 상태, 캔버스, 채팅 순서. 다른 게임 HTML과 동일한 showCustomAlert 모달과 .game-status phase 토글을 쓴다. bridge-cross:error 핸들러로 호스트 권한 부족이나 인원 부족 알림을 처리한다.

에셋 구조가 꽤 정갈하다. assets/bridge-cross/ 아래에 sprites/, stage/, _unused/로 분리됐다. 7색 캐릭터 스프라이트시트가 각각 4열 6행 1400x1122로 패킹됐다. 처음엔 loose contact sheet로 만들었는데 균등분할이 깨져서 전부 재패킹했다. 깨진 원본은 _unused/sprites/archive/에 보관. stage/는 레이어 분리 구조 — background-void, start-stage, finish-stage를 개별 PNG로 나눴다. 합성 이미지 하나를 쓰는 것보다 캔버스에서 레이어 단위로 그리는 게 유연하다.

bridge-cross-sprites.manifest.에 스프라이트 메타데이터를 정의했다. grid columns/rows, anchor 좌표, defaultScale, paletteOrder 등. 하드코딩 대신 manifest를 읽어서 쓰는 구조로 만들었다. 나중에 스프라이트 교체할 때 JSON만 수정하면 된다.

sound-config.에 9개 사운드 키를 placeholder로 추가했다. step, safe, crack, break, fall, betting_open 등. src 경로는 빈 문자열이다. 실제 오디오 파일은 후속 커밋에서 채운다.

결정론적 재생 구현이 이 게임의 기술적 핵심이다. 서버가 시나리오(어느 열이 안전한지, 각 캐릭터가 어디로 밟는지)를 정해서 내려주면, 클라이언트는 그 시나리오대로만 애니메이션을 재생한다. 난수가 클라이언트에 없으니 어떤 탭을 열어도 같은 결과가 나온다. UE5에서 리플레이 시스템을 구현할 때도 같은 원리를 쓴다 — 입력 시퀀스를 기록하고, 결정론적 시뮬레이션으로 재생한다.

index.html 로비에 4번째 게임 카드를 추가했다. #42edff 보더 색상으로 bridge-cross 테마 컬러를 정했다. routes/api.js도 정리했는데, 기존 경마 레거시 HTML 서빙 코드를 리팩토링하면서 bridge-cross 라우트를 같이 넣었다.

랭킹과 튜토리얼 통합은 이번 커밋에서 제외했다. impl 문서 §3.1.2.1, §5.5에 후속 단계로 명시해뒀다. 한 번에 다 넣으려다가 꼬이는 걸 방지하려고.

Co-Authored-By에 Claude Opus 4.7 (1M context)가 들어가 있다. 이 정도 규모의 다파일 통합 작업에서 AI가 실제로 코딩 파트너로 동작했다는 뜻이다.

서버가 시나리오를 결정하고 클라이언트는 재생만 한다 — 베팅 게임에서 결정론적 재생은 선택이 아니라 필수다.

← 이전 글
AI 업데이트: 에이전트가 DB를 날렸다, 그리고 OpenAI의 원칙 선언