⌥Space는 내 것이 아니었다
2026.08.29
일하는 화면 위에 야구장이 있다. 창을 띄우는 게 아니라 투명한 판을 한 장 덮고, 그 위에서 타자와 투수가 논다. 뒤에 있는 건 진짜 내 에디터고, 공은 그 코드 위를 가로질러 날아간다.
위 스크린샷은 실제로 돌아가는 화면이다. 뒤에 떠 있는 코드가 이 게임의 타구 계산 코드라는 게 좀 웃긴데, 그건 우연이 아니라 그때 그걸 만지고 있었기 때문이다.
8월 12일에 배포 페이지를 올리고, 18일에 조작키로 크게 한 번 데이고, 20일에 1.0.1, 29일에 1.1.0을 냈다. 그 사이에 배운 것을 적는다.
공은 오는데 스윙이 안 왔다
문의가 세 건 들어왔다. 전부 같은 증상이었다. 공은 날아오는데 스윙만 안 된다.
기본 조작키가 ⌥Space(윈도우 Alt+Space)였다. 그리고 그 조합은 내 것이 아니었다.
- 맥에서는 입력기가 먼저 가져간다. 한영 전환에 걸어둔 사람이 많다.
- 윈도우에서는
Alt+Space가 창 메뉴를 연다. 게다가Alt를 떼는 순간 크롬 메뉴까지 열린다.
전역 단축키에는 소유권이 없다. 먼저 잡는 쪽이 갖는다. 내 앱은 그 줄의 맨 끝에 서 있었다.
기본을 ⌥⇧로 바꿨다. 그리고 되돌렸다.
이미 손에 익은 사람에게서 조합을 빼앗는 건 모두가 치르는 비용인데, 문제는 일부에게만 있었다. 손해 보는 쪽을 뒤집은 셈이었다.
대신 트레이 메뉴에 조작키를 바꾸는 항목을 두고, 그 방법을 설치 안내에 한 줄씩 적었다. 「스윙이 안 되면 조작키를 바꾼다」가 설치 단계 중 하나다.
고칠 것은 기본값이 아니라 빠져나갈 길이었다. 안내가 없으면 사용자 입장에서는 그냥 고장 난 게임이고, 고장 난 게임은 두 번 열지 않는다.
잘 맞혔다고 다 안타가 아니다
1.1.0에서 외야수를 넣었다. 이게 게임을 통째로 바꿨다.
그전까지는 맞히면 무조건 좋은 일이었다. 타이밍이 정확할수록 공이 멀리 갔고, 멀리 가면 좋았다. 입력이 좋으면 결과가 좋은 일차함수였다.
외야수는 뜬공이 뜨면 낙구 지점으로 달려간다. 체공 시간 안에 닿으면 아웃이다.
잘 맞힐수록 홈런 아니면 아웃이 되고, 오히려 힘없이 맞은 공이 안타로 남는다. 잘 치는 것과 결과가 좋은 것이 갈라지는 순간 게임이 게임이 됐다.
여기에 예외를 하나 뒀다. 바운드된 공은 잡지 않는다. 안 그러면 땅볼이 전부 아웃이 되고, 잘 못 친 사람에게는 아무것도 안 남는다. 못 친 사람에게 남는 게 있어야 다음 공을 기다린다.
높낮이도 결과를 바꾼다. 같은 타이밍이라도 낮게 들어온 공은 발사각이 깎여 덜 날아간다. 20ms 안쪽으로 맞혀도 낮은 공이면 담장 앞에 떨어진다. 타이밍 하나로 결정되지 않게 하려고 넣은 축이다.
실패에 높이를 줬다
같이 넣은 게 팝파울이다. 빗맞은 공이 화면 위로 솟는다. 그런데 아무렇게나 솟지 않는다.
아깝게 빗맞을수록 높이 올라간다.
빗나간 정도가 화면에 그대로 보인다. 간발의 차로 놓친 것과 한참 멀었던 것이 다르게 생겼다. 실패가 그냥 실패로 끝나면 배울 게 없는데, 높이가 남으면 다음 공을 조금 다르게 기다리게 된다.
홈런에는 긴 잔상을 남겼다. 포물선이 통째로 화면에 남아서, 잘 친 공이 어떻게 생겼는지가 그림으로 남는다.
화면 끝에 떨어뜨리려고 91%를 남겼다
스크린샷에 떠 있는 코드가 이 이야기다.
// 튀고 구르는 거리를 바짝 줄인다 — 전체 거리의
// 91%가 날아간 거리(캐리)여야 홈런이 화면 반대편
// 끝에 "떨어지는" 것으로 보인다.
진짜 타구는 떨어지고 나서도 꽤 굴러간다. 그걸 그대로 두면 홈런이 화면 밖으로 미끄러져 나가 사라진다. 넘어가는 건 맞는데, 넘어가는 게 안 보인다.
그래서 구르는 몫을 9%까지 줄였다. 물리를 틀리게 만든 게 아니라, 화면이라는 크기에 맞춰 비율을 정한 것이다. 야구장은 타구가 다 구르고도 남지만 모니터는 안 그렇다. 홈런이 홈런처럼 보이려면 공은 화면 끝에서 떨어져야 한다.
비거리를 세는 방식도 같은 이유로 손봤다. 담장에 막혀 끊긴 타구도, 담장이 없었다면 떨어졌을 지점까지 세어 준다. 기록이 연속 안타가 아니라 비거리인 게임이라, 담장이라는 우연한 벽이 기록을 깎으면 안 됐다.
결과는 공이 알려준다
치자마자 답이 안 나온다.
- 홈런은 공이 담장을 넘는 순간, 담장 위에 뜬다.
- 안타는 공이 다 굴러 멈춘 자리에 뜬다.
- 그 글씨가 사라져야 다음 공이 온다.
판정을 구석 HUD에 띄우지 않았다. 눈은 공을 따라가고 있는데 답이 화면 구석에 뜨면 둘 중 하나는 못 본다. 답을 공이 있는 자리에 붙여두면 시선을 옮길 필요가 없다.
늦게 알려주는 것도 일부러다. 결과가 즉시 나오면 공이 날아가는 1초가 그냥 기다리는 시간이 된다. 답을 공 끝에 매달아 두면 그 1초가 지켜보는 시간이 된다.
난이도를 글자로 쓰지 않았다
1.1.0에서 투수를 끌어서 옮길 수 있게 했다. 당기면 공이 일찍 와서 어려워지고, 밀면 쉬워진다. 메뉴에서 고를 수도 있다.
「쉬움 · 보통 · 어려움」이라고 쓸 수도 있었다. 그런데 그건 고르고 나면 무슨 뜻인지 모른다. 어려움이 얼마나 어려운지는 해보기 전엔 알 수 없고, 해보고 나서도 숫자가 뭘 바꿨는지는 안 보인다.
투수가 가까이 서 있는 건 보면 안다. 그리고 끌어당기는 손짓 자체가 「이만큼 어렵게」라는 뜻이 된다. 난이도를 설정이 아니라 거리로 준 것이다.
몰래 하려면 지켜야 하는 것들
이름이 「몰래 야구」라서 생기는 제약이 있다.
Dock에 아이콘이 없다. 메뉴 막대의 야구공 하나가 전부다. 최고 비거리도 종료도 거기서 한다.
⌘⇧B로 숨긴다. 한 번 더 누르면 돌아온다.
⌥를 누르고 있는 동안만 투수가 던진다. 떼면 바로 멈춘다. 손을 뗐는데 화면에서 공이 계속 날아다니면 그건 몰래가 아니다.
그리고 손쉬운 사용 권한을 하나도 요구하지 않는다. 그 권한 창이 뜨는 순간 이미 몰래가 아니다. 전역 입력을 가로채는 대신 누르고 있는 동안만 도는 구조를 고른 것도 그래서다.
유니폼은 KBO 10개 구단의 홈·원정 20벌을 넣고 타자와 투수에게 따로 입힌다. 처음엔 롯데를 입고 나온다. 모니터가 여러 대면 어느 화면에 띄울지도 고른다 — WebSwing에서 겪은 것과 같은 문제라 이번엔 처음부터 넣었다.
주소는 그대로 두고 버전만 내린다
1.1.0을 올리면서 버전 전체 보기를 붙였다.
받는 주소는 최신만 고정이다. 파일 이름에 버전을 달면 새 빌드마다 크롬과 SmartScreen 입장에서 세상에 처음 나온 파일이 되고, 조금씩 쌓이던 다운로드 평판이 매번 0으로 돌아간다. 지난 버전은 평판을 쌓을 일이 없으니 버전 폴더로 내려보낸다.
이건 WebSwing에서 한 번 데이고 규칙으로 굳힌 것이다.
남은 것
이 게임은 남의 화면 위에 얹혀 산다. 그래서 고친 것 대부분이 내 것이 아닌 걸 내 것처럼 쓴 자리였다. 단축키도, 화면도, 다운로드 주소에 쌓인 신뢰도도 전부 빌려 쓰는 것이었다.
게임 쪽에서 고친 것은 전부 반대 방향이었다는 게 재미있다.
- 잘 친 공을 덜 좋게 만들었다 (외야수)
- 실패에 높이를 줬다 (팝파울)
- 답을 늦게 알려줬다 (공이 멈춘 자리)
- 물리를 깎았다 (구르는 몫 9%)
넷 다 「더 좋게」가 아니라 「덜 바로」였다. 만들 때는 잘하면 잘한 만큼 보상하는 쪽이 옳아 보이는데, 그렇게 만든 게임은 두 번째 공이 궁금하지 않다.
결과가 바로 안 나와야 결과를 기다리게 된다.
같이 읽으면 좋은 글
좁은 창은 빼지 않고 눕혔다
자리를 비우면 트로이 목마에서 병사가 쏟아져 열려 있는 창을 점령하는 맥 앱을 만들었다. 하루 동안 페이지를 만들고, 거르던 예외를 되살리고, 써 둔 설명을 여섯 문단 지웠다.
데스크톱macOS설계2026.08.07두 번째 모니터는 못 가는 게 아니라 갈 곳이 없었다
창 모서리에 거미줄을 걸고 날아다니는 데스크톱 펫을 하루 종일 고쳤다. 클릭이 씹히고, 두 번째 모니터가 없는 셈이 되고, 다른 화면을 누르면 벽으로 돌진했다. 전부 좌표계를 하나로 믿은 코드였다.
데스크톱좌표계윈도우2026.08.05추첨기에 귀여운 걸 붙였더니 물리가 거짓말을 했다
코인 밀기 추첨기에 캐릭터 스킨을 붙였다. 토끼 귀를 그리는 순간 "닿지도 않았는데 밀렸다"가 보이기 시작했고, 회전각에 표정을 걸었더니 눈이 지글거렸다. 겉모습만 바꾸는 작업에서 지켜야 했던 네 가지.
게임캔버스디자인2026.07.30