키보드 전용 브라우저 게임에 터치 조작을 어떻게 추가할까요?
게임이 이미 이해하는 입력을 전달하는 별도의 터치 레이어를 게임 위에 얹으세요. KittenGalaxy에서 이렇게 한 방법과 아직 테스트하지 못한 부분을 소개합니다.

터치를 게임이 이미 처리하는 입력으로 바꿔 주는 별도의 화면 조작 레이어를 추가하고, 게임의 화면마다 다른 조작 버튼을 보여 주세요. 게임을 다시 작성할 필요는 없습니다. 저희는 이 방법으로 KittenGalaxy를 휴대폰에서 플레이할 수 있게 만들었고, 이 글에서는 아직 테스트하지 못한 부분을 포함해 그 결정들을 차례로 설명합니다.
게임은 원래 무엇을 기대했나요?
KittenGalaxy는 canvas에 그림을 그리는 JavaScript 파일 하나로 작성된 아케이드 슈팅 게임입니다. 모든 입력은 세 가지 방식으로 들어왔습니다. 비행, 사격, 메뉴를 위한 키 입력, 파일럿 이름을 위한 문자 입력, 그리고 상점 목록과 수학 챌린지에서 canvas에 그려지는 숫자 패드를 위한 마우스 클릭입니다.
휴대폰에서는 플레이어가 누를 것이 없습니다. 키가 없고, canvas의 숫자 키는 너비 720유닛의 플레이 영역에서 38유닛 너비로 그려지기 때문에 너비 375픽셀인 휴대폰에서는 약 20 CSS 픽셀밖에 되지 않습니다. 안정적으로 누르기에는 너무 작습니다.
터치는 공유 입력 상태를 바꿔야 할까요, 키 이벤트를 보내야 할까요?
흔한 설계는 두 가지입니다.
| 방식 | 작동 원리 | 적합한 경우 |
|---|---|---|
| 공유 입력 상태 | 키보드와 터치 핸들러가 모두 left나 fire 같은 플래그를 설정하고, 게임 루프는 플래그만 읽습니다 | 게임 코드가 내 것이고 입력을 읽는 방식을 바꿀 수 있을 때 |
| 합성 키 이벤트 | 터치 레이어가 keydown과 keyup 이벤트를 보내고, 게임의 기존 리스너가 이를 받습니다 | 게임 코드를 그대로 두어야 할 때 |
공유 상태가 더 깔끔한 설계이며, 오늘 게임을 시작한다면 그렇게 만드세요. 저희가 합성 키 이벤트를 고른 이유는 하나입니다. KittenGalaxy는 다른 곳에서 개발되고 있고, 저희는 그 파일을 받은 그대로 바이트 단위까지 유지합니다. 그래야 새 버전을 받을 때 저희의 변경을 다시 하지 않아도 됩니다. 스크립트로 만든 이벤트도 일반 리스너에 그대로 전달됩니다. 브라우저 자체의 기본 동작은 일으키지 않지만, 게임에는 그것이 필요 없습니다.
터치 레이어는 게임이 지금 어느 화면에 있는지도 알아야 합니다. 이를 위해 빌드 단계에서 작은 읽기 전용 객체 하나를 추가해, 현재 상태나 로켓 장착 여부 같은 몇 가지 값을 노출합니다. 이 객체로는 게임을 바꿀 수 없습니다.

화면마다 어떤 조작 버튼이 필요할까요?
고정된 버튼 한 세트가 흔한 첫 시도이지만, 게임에 메뉴가 생기는 순간 통하지 않습니다. 모든 화면과 그곳에서 플레이어가 할 수 있어야 하는 일을 적어 보세요.
| 화면 | 플레이어에게 필요한 것 | 저희가 보여 주는 것 |
|---|---|---|
| 메뉴 | 시작, 파일럿 전환 또는 추가 | 큰 주 버튼 하나와, 해당될 때만 나타나는 작은 버튼들 |
| 파일럿 이름 짓기 | 이름 입력 | 휴대폰이 키보드를 띄우도록 진짜 텍스트 입력란 |
| 비행 | 이동, 사격, 추가 장비 사용, 일시 정지 | 엄지 스틱, 자동 사격, 보유한 뒤에만 나타나는 추가 장비 버튼 |
| 상점 | 둘러보고 구매 | 탭과 화살표 버튼. 행을 탭하면 선택, 다시 탭하면 구매 |
| 수학 챌린지 | 숫자 입력 | 실제 크기의 숫자 패드 |
| 게임 오버, 엔딩 | 계속하거나 나가기 | 버튼 두 개 |
예상보다 중요했던 세 가지가 있습니다.
글자 입력에는 진짜 텍스트 입력란을 쓰세요. 포커스를 받은 입력란만 휴대폰의 키보드를 띄웁니다. 그 입력란 자체의 키 입력은 게임에 전달하지 않고, 완성된 이름을 한 번에 게임에 입력합니다.
손가락은 호버할 수 없습니다. 마우스로는 상점의 행을 가리키면 선택되고 클릭하면 구매됩니다. 탭은 두 가지를 한꺼번에 해 버려서 실수로 구매하기 쉽습니다. 레이어는 행을 처음 탭하면 선택으로 바꾸고, 두 번째 탭을 구매로 통과시킵니다.
해당되지 않는 것은 숨기세요. 로켓 버튼은 로켓을 장착했을 때, 폭탄 버튼은 폭탄을 가지고 있을 때 나타납니다. 버튼이 적을수록 버튼을 크게 만들 수 있습니다.
엄지 스틱은 어떻게 만들까요?
게임의 우주선은 방향키처럼 여덟 방향으로 움직이므로, 스틱은 어떤 방향키가 눌려 있는지만 정하면 됩니다. 저희 스틱은 엄지가 닿은 자리에 나타나고, 12픽셀 데드존 안의 움직임은 무시하며, 엄지가 해당 축으로 충분히 멀어지면 그 방향을 눌린 것으로 처리합니다.
const DEAD = 12;
function steer(dx, dy) {
const far = Math.hypot(dx, dy) > DEAD;
const want = {
ArrowLeft: far && dx < 0 && Math.abs(dx) >= Math.abs(dy) * 0.41,
ArrowRight: far && dx > 0 && Math.abs(dx) >= Math.abs(dy) * 0.41,
ArrowUp: far && dy < 0 && Math.abs(dy) >= Math.abs(dx) * 0.41,
ArrowDown: far && dy > 0 && Math.abs(dy) >= Math.abs(dx) * 0.41,
};
// press the keys that became true, release the ones that became false
}
0.41은 22.5도의 탄젠트 값으로, 원을 똑같은 여덟 조각으로 나눕니다. 엄지가 가장자리를 넘어가면 스틱의 중심이 따라오므로, 방향을 바꿀 때 긴 움직임 대신 작은 움직임이면 됩니다.
터치, 펜, 마우스를 하나의 핸들러 세트로 다루는 포인터 이벤트와, 엄지가 스틱 밖으로 미끄러져도 계속 받을 수 있게 해 주는 포인터 캡처를 사용했습니다. 사격은 기본적으로 자동이며, 사격 버튼을 선호하는 플레이어를 위한 스위치가 있습니다. 한 판 내내 엄지를 누르고 있으면 피곤하고, 슈팅 게임은 계속 쏘더라도 잃는 것이 거의 없습니다.
브라우저가 게임과 충돌하지 않게 하려면?
브라우저는 따로 알려 주지 않으면 터치를 스크롤, 확대, 텍스트 선택으로 처리합니다.
- 게임과 조작 버튼에 [
touch-action: none](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/touch-action)을 설정해 드래그를 직접 처리하세요. - 게임 위에서는 텍스트 선택과 길게 누르기 메뉴를 끄세요.
- 창이 포커스를 잃으면 누르고 있던 키를 모두 떼세요. 그러지 않으면 알림이 화면을 차지한 뒤에도 우주선이 계속 왼쪽으로 날아갑니다.
- 소리는 실제 탭에서 시작하세요. 브라우저는 플레이어가 페이지와 상호작용한 뒤에만 오디오를 허용하므로, 첫 탭이 게임의 오디오도 깨웁니다.
- 조작 버튼은 그리기 루프뿐 아니라 타이머로도 갱신해서, 첫 프레임이 그려지기 전에 알맞은 버튼이 나와 있게 하세요.
- 게임이 비워 두는 띠를 활용하세요. 세로 화면에서는 정사각형 플레이 영역이 가운데에 있으므로 조작 버튼은 위아래의 검은 띠에 둡니다. 가로 화면에서는 모서리에 두고 흐리게 표시합니다.
무엇을 테스트했고, 무엇을 하지 않았나요?
출시일인 2026년 10월 8일, 휴대폰 크기로 설정한 데스크톱 브라우저에서 세로(375 × 812)와 가로(812 × 375)로 터치 레이어를 확인했습니다. 스크립트로 만든 터치로 조작해, 텍스트 입력란으로 파일럿 만들기, 게임 시작, 스틱의 여덟 방향 전부, 상점, 숫자 패드로 수학 문제에 답하기를 살펴봤습니다.
실제 휴대폰이나 태블릿에서는 아직 플레이해 보지 못했습니다. 에뮬레이션으로는 진짜 엄지 아래에서 스틱이 어떤 느낌인지, 휴대폰마다 키보드가 어떻게 동작하는지, 느린 기기가 어떻게 버티는지 알 수 없습니다. 게임 페이지의 모바일 브라우저 항목에 바로 이 내용이 적혀 있으며, 실제 기기에서 확인하면 고치겠습니다. 휴대폰에서 플레이해 보셨다면, 기기와 겪은 일을 적은 리뷰가 보내 주실 수 있는 가장 유용한 정보입니다.
자주 묻는 질문
터치 조작에 게임 엔진이 필요한가요? 아니요. 버튼은 canvas 위에 놓인 평범한 HTML 요소이고, 어느 버튼이 눌렸는지는 브라우저가 판단합니다.
버튼은 canvas에 그려야 하나요, HTML로 만들어야 하나요? 대부분 HTML입니다. 터치 판정, 멀티터치, 접근성 레이블을 직접 작성하지 않아도 되고, CSS로 모양을 바꿀 수 있습니다.
터치 버튼은 얼마나 커야 하나요? 플레이 중에 누르는 버튼은 세로 화면에서 각 변이 최소 46 CSS 픽셀이고, 주요 버튼은 더 큽니다. 모서리의 보조 버튼 몇 개는 일부러 더 작게 만들었습니다. 저희가 대체한 canvas 키는 약 20이었습니다.
플레이어가 숨겨진 제스처를 찾아낼까요? 찾지 못한다고 가정하세요. 저희 레이어의 모든 동작에는 눈에 보이고 이름이 붙은 버튼이 있습니다.
모바일 조작이 완성되기 전에 HeapPlay에 게임을 등록할 수 있나요? 네. 각 플레이 방법은 따로 등록되고 확인되므로, 지금은 데스크톱 방법으로 게임을 제출하고 모바일은 나중에 추가할 수 있습니다. 그 뒤로는 인증된 개발자가 각 버전을 직접 기록할 수 있습니다. 개발자가 받는 것을 참고하세요.
touch-controls mobile browser-games
게임을 만들고 계신가요? HeapPlay에 제출하고 개발자가 받는 것을 확인해 보세요.