🤖
1975 in / 1734 out / 3709 total tokens
beginPlayer에서 return 처리할 때 BRIDGE_COLUMNS라는 서버 전용 상수를 클라이언트 IIFE 내부에서 그대로 참조하고 있었다. 당연히 undefined고, layout.tileCenter(undefined - 1, 'top')은 NaN을 뱉는다. moveAvatar(NaN, NaN)이 호출되면 캐릭터 좌표가 NaN으로 박혀서 화면에 안 보이는 현상이 발생했다. 유저 피드백이 "다시 안 돌아오고 있어"였는데, 디버그 로그 찍어보니 좌표가 NaN이더라. 원인 파악하고 나니 허탈했다. layout.columnCount로 교체해서 해결.
이 버그의 핵심은 서버와 클라이언트의 상수 스코프가 다르다는 걸 놓쳤다는 거다. 서버 코드에서 BRIDGE_COLUMNS를 전역으로 정의해두면, 같은 파일을 브라우저에서 IIFE로 감싸서 실행할 때 그 변수는 스코프 밖에 있다. UE5 작업할 때도 서버-클라이언트 간 상수 동기화 문제는 항상 골치 아픈데, 여기서도 똑같은 실수를 했다. 앞으로는 공유 상수는 별도 모듈로 빼거나, 클라이언트에서 layout 객체의 프로퍼티로만 참조해야겠다.
javascript // before: BRIDGE_COLUMNS는 서버에만 존재 → NaN return layout.tileCenter(BRIDGE_COLUMNS - 1, 'top');
// after: layout.columnCount 사용 return layout.tileCenter(layout.columnCount - 1, 'top');
두 번째 변경은 다리 reset 시각 효과다. 이전 커밋에서 fxSheet rows를 6→7로 늘리고 restore_glass 애니메이션 정의를 manifest에 추가해뒀는데, 이번 커밋에서 실제 렌더 로직을 구현했다. 깨진 타일 위에 restore_glass 프레임을 그리면서 alpha fade를 적용하는 방식이다. glass-fx-v2.png 스프라이트시트에 7번째 줄(row 6)이 추가됐고, manifest.에 restore_glass 애니메이션 정의도 들어갔다.
이펙트 구현은 기존 break_shards랑 비슷한 패턴이다. broken 상태인 컬럼 위에 restore_glass 애니메이션을 오버레이로 그리고, 재생이 끝나면 alpha를 서서히 줄여서 자연스럽게 사라지게 만들었다. 스프라이트 시트 row 하나 추가하고 manifest 업데이트하는 파이프라인은 이미 깨져 있어서 작업 자체는 깔끔하게 끝났다.
추가로 beginPlayer에 디버그 로그를 넣었다. stage/player/from/to 좌표를 찍어서 return 진입 시 좌표가 어떻게 계산되는지 추적할 수 있게 했다. 이게 없었으면 NaN 버그 잡는 게 훨씬 오래 걸렸을 것이다. 문제 발생 지점에 로그부터 박는 건 게임 클라 개발의 기본이지만, 막상 급하면 까먹는다. 이번엔 Claude가 로그 추가를 제안해줘서 빠르게 잡을 수 있었다.
Co-Authored-By로 Claude Opus 4.7이 들어간 걸 보면, 이 버그 원인 분석과 패치를 Claude와 페어 프로그래밍으로 진행한 모양이다. 1M context 모델이라 프로젝트 전체 맥락을 물고 들어와서 도움이 됐을 듯.
서버 상수를 클라이언트 IIFE에서 그대로 쓰면 NaN이 된다. 당연한 건데 당하면 허탈하다.