매치 시즈를 폰에서 돌릴 수 있게 만들었습니다. 두 가지가 필요했습니다. 손가락으로 블록을 미는 것, 그리고 닉네임을 한글로 넣는 것.

터치를 마우스로 번역하지 않았습니다

엔진에는 터치를 마우스 이벤트로 바꿔 주는 기능이 있습니다. 그걸 켜면 코드를 안 고쳐도 일단 돌아갑니다. 안 썼습니다.

번역된 이벤트는 진짜 마우스와 미묘하게 다릅니다. 드래그 중 버튼이 눌린 상태로 표시되는지, 눌림과 움직임의 순서가 어떤지 같은 것들입니다. 그 차이가 "데스크톱에서만 되는 버그"가 자라는 자리입니다.

대신 터치와 마우스를 같은 세 함수로 모았습니다. 눌림, 끌림, 뗌. 위쪽에서 어느 장치가 들어왔든 아래쪽은 하나입니다. 갈라질 자리가 없으면 갈라진 채로 굳는 일도 없습니다.

자모를 이어 붙이면 글자가 안 됩니다

닉네임 입력이 진짜 문제였습니다. 캔버스로 그리는 게임은 브라우저의 한글 입력기를 받지 못하고, 폰에는 물리 키보드가 없습니다. 그래서 자판과 조합기를 둘 다 만들었습니다.

한글은 자모를 나열해서 되는 글자가 아닙니다. ㅎ, ㅏ, ㄴ을 그냥 이어 붙이면 'ㅎㅏㄴ'이지 '한'이 아닙니다. 조합기가 해야 하는 일은 이런 것들입니다.

  • 받침이 다음 초성으로 넘어가는 것 — '한' 다음에 ㄱ이 오면 '하' + '나'가 아니라 '한' + 'ㄱ'이었다가, 모음이 오면 받침 ㄴ이 떨어져 나가 '하' + '나'가 됩니다
  • 겹받침 분리 — '앉'에서 모음이 오면 ㄴ만 남고 ㅈ이 넘어갑니다
  • 복합 모음 — ㅗ + ㅏ = ㅘ
  • 단계별 지우기 — 지우기 한 번에 글자 하나가 통째로 날아가면 안 됩니다. 조합 중인 자모 하나씩 물러나야 합니다

자판 쪽은 두벌식과 영문 전환, 시프트, 숫자행을 넣었습니다. 레이아웃을 순수 함수로 만든 게 이번에 잘한 일입니다. 그리기와 터치 판정이 같은 함수를 부르니까, 눈에 보이는 자리와 실제로 눌리는 자리가 어긋날 수가 없습니다. 이게 갈라지면 "분명히 ㄱ을 눌렀는데 ㄴ이 찍히는" 버그가 되고, 그건 화면만 봐서는 절대 못 찾습니다.

물리 키보드도 같은 조합기를 지나게 했습니다. 데스크톱은 데스크톱대로 따로 처리하고 싶은 유혹이 있는데, 편집 경로가 두 벌이면 반드시 어긋납니다.

셀프테스트는 204항목이 됐습니다. 한글 조합만 스무 항목쯤이고, 자판 키가 서로 겹치지 않는지와 좌표를 눌렀을 때 의도한 키가 잡히는지도 같이 봅니다.

뒤로가기로 그냥 꺼지던 것

안드로이드에서 뒤로가기를 누르면 앱이 즉시 종료됐습니다. 되돌릴 수 없는 동작인데 스치듯 눌리기 쉬운 버튼입니다. 물어보고 닫도록 바꿨습니다.

이걸 별개 화면이 아니라 모달로 만들었습니다. 화면 종류를 늘리면 뒤로가기, 그리기, 버튼 처리를 전부 손봐야 하는데 이건 타이틀 위에 잠깐 뜨는 것이니까요.

여기에 함정이 있었습니다. 창이 떠 있는 동안 뒤에 깔린 버튼이 살아 있으면 안 됩니다. 종료를 묻는 중에 PLAY가 눌려 게임이 시작되면 그거야말로 최악입니다. 버튼 목록을 돌려주는 함수가 그리기와 터치 판정의 단일 출처라, 거기 한 곳에서 막으니 양쪽 다 막혔습니다.

기본 강조는 '계속하기'입니다. 실수로 한 번 더 누르는 쪽이 종료가 되면 안 됩니다. 그리고 '기록과 설정은 그대로 남습니다'를 적어 뒀습니다. 종료를 망설이는 이유는 보통 뭔가 잃을까 봐인데, 안 잃는다고 말해 주면 판단이 쉬워집니다.

이 셋은 화면만 봐서는 확인이 안 되는 것들이라 자동 검사에 항목으로 넣었습니다. 버튼 목록이 정말 두 개뿐인지 같은 건 스크린샷으로는 알 수 없습니다.

이어서 읽을 것

웹 캔버스가 브라우저의 기본 동작과 어긋나는 자리는 여기만이 아닙니다. 브라우저가 준 숫자를 그냥 믿고 있었습니다도 같은 종류이고, 실기기에서만 나온 것들은 데스크톱에서는 절대 볼 수 없던 결함 둘에 있습니다.