네 개의 네온 선 위를 달리다: 네온 레인 개발부터 구글 플레이 출시까지

빨강·주황·노랑·초록, 네 개의 네온 선 위를 박자에 맞춰 달리는 리듬 러너 네온 레인(Neon Lane) 을 구글 플레이에 출시했습니다. 레이싱 게임으로 시작했다가 방향을 바꾼 이유, 개발 중 가장 크게 고친 문제들, 12명 14일 비공개 테스트와 프로덕션 승인, AdMob 앱 인증까지의 과정을 시간 순서대로 정리했습니다.

네온 레인 스토어 대표 이미지

1. 왜 이 게임을 만들었나

처음 아이디어는 스케이트보드 선수가 세로로 놓인 네 개의 차선을 오르내리는 게임이었습니다. 이어서 4차선 자동차, 주유와 타이어 교체 같은 선택 타이밍을 넣은 배달 레이싱 게임까지 만들어 봤습니다. 그런데 해 보니 너무 식상했습니다. 이동 규칙이 단순한 만큼 “이 게임이어야 하는 이유”가 약했습니다.

그래서 방향을 바꿨습니다.

  • 검은 사이버 도시 배경 위에 빨주노초 네 개의 선이 있고, 그 위를 빛 하나가 박자에 맞춰 이동한다.
  • 충돌하는 것은 차가 아니라 음표 블록. 음악이 곧 장애물이다.
  • 박자에 맞춰 움직이면 점수와 콤보가 올라가는, 리듬이 곧 규칙인 러너.

이 규칙이면 조작은 ◀ ▶ JUMP 세 개뿐이라 한 손으로 할 수 있고, 매일 같은 곡을 모두가 함께 겨루는 일일 랭킹도 자연스럽게 얹을 수 있습니다.

개발은 앞서 출시한 그라비워프와 같은 방식으로, Claude Code(AI 코딩 도구)와 함께 진행했습니다. 기획과 방향 결정은 제가 하고, 구현·테스트·빌드는 AI가 맡고, 결과는 매번 제가 직접 폰으로 확인했습니다.

2. 게임 소개: 박자에 맞춰 네 개의 선 위를

규칙은 다음과 같습니다.

  • ◀ ▶ 로 차선을 옮기고 JUMP로 낮은 막대를 넘는다.
  • 블록을 피하거나 노트(◆)를 향해, 막대를 넘으려고 박자에 맞춰 움직이면 PERFECT. 콤보가 쌓이면 점수 배수(최대 ×4)가 올라간다.
  • 음표 블록에 한 번 부딪히면 끝.
  • 달릴수록 BPM과 속도가 올라가다가 170 BPM에서 유지된다.

네온 레인 타이틀 화면 네온 레인 플레이 화면

이벤트 3종: 화면이 돌아간다

게임을 달리다 보면 화면이 갑자기 바뀝니다. 버튼은 진행 방향 기준으로 ◀=왼쪽이 되도록 같이 바뀝니다.

이벤트 화면 버튼
이벤트 1 가로로 전환, 왼쪽에서 오른쪽으로 진행 ◀ = 위, ▶ = 아래
이벤트 2 가로로 전환, 오른쪽에서 왼쪽으로 진행 ◀ = 아래, ▶ = 위
이벤트 3 상하 반전 ◀ = 오른쪽, ▶ = 왼쪽

이벤트 1: 가로 전환 이벤트 2: 반대 방향 가로 전환 이벤트 3: 상하 반전

처음 만든 이벤트 2는 이벤트 1과 버튼 방향이 같아서 헷갈린다는 의견이 있어서, 이벤트 1을 180° 회전한 모양으로 바꿨습니다. 그래야 “진행 방향 기준 ◀가 왼쪽”이라는 규칙이 세 이벤트 모두에서 같아집니다.

매일 바뀌는 패턴과 음악, 그리고 랭킹

  • 일일 랭킹: 매일 모든 플레이어가 같은 곡으로 겨룹니다. 점수는 서버(Firebase)에 올라가고 닉네임만 있으면 시작할 수 있습니다.
  • 명예의 전당: 일일 1위 기록이 남습니다.
  • 매일 바뀌는 구성: 장애물 배치뿐 아니라 코드 진행 6종, 키(조), 킥 드럼 변주, 아르페지오 순서·옥타브·음색이 날짜(곡 시드)에 따라 바뀝니다. 같은 날은 모든 사람이 같은 곡을 듣습니다.

결과 화면

3. 개발 타임라인

날짜 내용
9월~10월 초 스케이트보드 → 배달 레이싱 → 리듬 러너로 방향 전환, 핵심 규칙과 이벤트 3종, 매일 달라지는 곡, 일일 랭킹·명예의 전당, PWA, 팀 로고 배지
10/6 안드로이드 앱화, Play Console 앱 만들기, 스토어 등록정보·앱 콘텐츠 입력, AdMob 광고 단위 발급, 첫 비공개 테스트 제출
10/7 랭킹 서버를 전용 Firebase 프로젝트로 분리
10/12 테스터 제보 반영: 점수 불균형 수정, 광고를 게임 시작 전에 표시, 상하반전 전환 수정, Play 스토어 업데이트 안내 추가
10/17 화면 전환 중 장애물 제거, 후반 화면 떨림 완화
10/23 음질 개선, 초반 속도 상향, 곡마다 달라지는 음악, 지직거림을 줄이는 가벼운 오디오 엔진으로 교체
10/25 업데이트 안내 팝업 속도 개선 (1.0.9)
10/28 프로덕션 액세스 신청
10/29 프로덕션 승인, IARC 콘텐츠 등급 확정
10/31 AdMob app-ads.txt 추가, 앱 인증 통과

4. 기술 스택

영역 사용 기술
게임 HTML5 Canvas 2D (논리 해상도 160×288을 화면에 맞춰 확대)
음악·효과음 파일 없이 Web Audio로 합성 (드럼·베이스·패드·아르페지오)
안드로이드 앱 Capacitor 8 (웹 게임을 앱으로 감싸기)
랭킹 서버 Firebase Firestore + 익명 로그인
광고 Google AdMob 배너·전면 광고, 유럽·영국 동의 화면
업데이트 안내 Play 스토어 앱 업데이트 정보 확인
설치 크기 신규 설치 약 7MB

그래픽과 음악 모두 이미지·음원 파일 없이 코드로 만든 것이라 용량이 작고 해상도에 구애받지 않습니다.

5. 안드로이드 앱으로 만들기

처음에는 웹 게임을 안드로이드 앱으로 만들 도구(Gradle, Android SDK)가 개발 환경에 없었습니다. 그래서 SDK 없이 앱 패키지(AAB)를 직접 조립했습니다. 화면을 보여주는 간단한 WebView 앱을 만들고, 리소스 컴파일러와 번들 도구로 패키징하고, 업로드 키로 서명했습니다.

그런데 광고(AdMob) 를 넣으려면 Google이 제공하는 라이브러리가 필요했고, 이건 Gradle 없이는 붙일 수 없었습니다. 그래서 Capacitor 프로젝트로 갈아탔습니다. 네트워크 허용을 열고 Android SDK 36을 설치해서 Gradle로 서명된 AAB를 빌드했습니다. 결과 파일은 업로드 키로 서명하고, Play 앱 서명을 사용합니다.

버전마다 AAB를 새로 빌드해서 비공개 테스트에 올렸습니다. 올리기 전에 서명, 버전 코드, 광고 ID, 서버 설정이 들어갔는지 AAB 안을 직접 확인했습니다.

6. 가장 기억에 남는 문제들

테스터의 제보가 곧 수정 목록이었습니다.

① 필요 없는 좌우 이동으로 점수가 44배

테스터 한 분이 “단지 살기 위해 조작하는 것과 계속 좌우로 움직이는 것의 점수 차이가 5배”라고 알려줬습니다. 코드를 보니 원인은 콤보 배수와 입력 점수였습니다. 박자에 맞춰 좌우·점프를 누르면 필요한 이동인지와 상관없이 PERFECT 점수와 콤보가 쌓이고, 배수는 ×8까지 올랐습니다.

같은 곡에서 100박을 시뮬레이션해 봤습니다.

방식 수정 전 수정 후
필요할 때만 피하기 약 3,000 약 2,400
박자에 맞춰 무의미하게 좌우 흔들기 약 132,000 약 5,900

수정은 세 가지였습니다. ① 필요한 입력(곧 막힐 레인에서 벗어나기, 가까운 노트의 레인으로 이동, 막대 점프)에만 점수와 콤보 부여, ② 노트를 놓치면 콤보 끊김, ③ 배수 ×8 → ×4, 한 박에 인정되는 입력은 1회. 무의미한 이동의 점수가 약 20분의 1로 줄었습니다.

② 상하반전이 되면 바로 죽는다

“상하반전에서 시야가 완전히 가려져서 죽는다”는 제보였습니다. 원인은 전환 방식이었습니다. 화면이 뒤집힐 때 위치를 직선으로 섞고 있어서, 중간 지점에서 네 개의 레인과 모든 노트가 화면 중앙의 한 점으로 모였다가 펼쳐졌습니다. 전환 중 약 0.3초 동안 노트가 전혀 보이지 않았던 것입니다.

수정 전(왼쪽)은 모든 노트가 한 점에 겹치고, 수정 후(오른쪽)는 레인이 기울어진 채로 모두 보인다 왼쪽: 수정 전, 전환 중간 프레임. 모든 레인과 노트가 한 줄로 겹친다. 오른쪽: 수정 후, 중심을 기준으로 180° 회전하므로 레인이 겹치지 않는다.

중심 기준 회전으로 바꿔서 전환 중에도 모든 노트가 보이게 했습니다. 안내 문구가 플레이 영역을 가리던 것도 위쪽으로 옮겼습니다.

③ 전환 구간의 점프 방해

가로·세로·상하반전 전환 중에 점프가 필요한 장애물이 나와서 방해된다는 제보도 있었습니다. 전환 시간을 초 단위로 고정해 두니 BPM이 빨라질수록 전환이 박 단위로는 길어졌고, 장애물을 비워 둔 구간(앞뒤 1박)보다 길어졌던 것이 원인이었습니다. 전환 시간을 0.6초로 고정하고 전환 앞뒤 2.2박은 장애물을 완전히 비웠습니다. 서로 다른 곡 시드 7개의 이벤트 91개를 검사해서 그 구간에 장애물이 하나도 없는 것을 확인했습니다.

④ 광고가 게임 중에 뜬다

“다시 하기를 누르면 게임이 시작된 뒤에 광고가 떠서 죽는다”는 제보였습니다. 전면 광고를 게임오버 직후에 불러오고 있었는데, 광고 로딩이 느리면 “다시 하기”를 누른 뒤에야 광고가 떴던 것입니다. 이제 게임오버 때는 광고를 부르지 않고, “다시 도전” 2번에 1번, 게임을 시작하기 전에 광고를 보여주고 닫힌 뒤에 게임이 시작됩니다. 광고가 4초 안에 준비되지 않으면 건너뜁니다.

⑤ 후반에 화면이 떨려 보인다

속도가 빨라지면 눈이 어지럽다는 제보였습니다. 하나의 원인이 아니라서 여러 가지를 줄였습니다. 이벤트 시작 때 화면을 흔들던 효과를 없앴고, 번쩍이는 효과와 박자마다 깜빡이던 배경을 줄였고, 최고 BPM을 낮췄고, 프레임 간격을 평활화하고, 해상도 상한을 2배로 정하고, 글로우 연산을 줄였습니다. 이런 효과를 줄이는 “눈 편한 모드” 는 기본으로 켜 두었고 설정에서 끌 수 있습니다.

설정 화면: 눈 편한 모드와 가벼운 사운드

⑥ 지직거리는 배경음

“소리가 거칠고 후반에 지직거린다”는 제보가 가장 오래 걸렸습니다. 처음에는 음색을 다듬었습니다. 엔벨롭, 필터, 스테레오 잔향, 컴프레서를 넣어 음량을 높이고 박자 흔들림도 줄였습니다. 그런데 “여전히 지직거린다”고 했고, 측정해 보니 내가 만든 개선이 오히려 이전보다 4배 무거웠습니다.

엔진 20초 분량 처리 속도(실시간 대비)
처음 엔진 11.7배
음질 개선 후(박자마다 소리를 실시간 합성) 2.9배
샘플 기반 엔진 18.6배 (가벼운 모드 37.6배)

실시간 합성은 박자마다 소리 노드를 20개 넘게 만들었고 무거운 잔향까지 돌렸습니다. 이 샌드박스에서 이 정도라면 폰에서는 처리가 밀려 지직거릴 수밖에 없었습니다. 그래서 소리를 미리 샘플로 구워 두고 재생할 때는 노드 1~3개만 쓰는 구조로 교체했고, 에코도 샘플에 구웠습니다. 설정에는 “가벼운 사운드” 옵션을 추가했습니다.

⑦ 업데이트 안내가 느리게 뜬다

버전을 올릴 때마다 테스터가 업데이트를 놓쳤습니다. 그래서 새 버전이 있으면 앱 시작 시 “새 버전이 나왔어요” 팝업을 띄워 Play 스토어 업데이트 화면으로 보내는 기능을 넣었습니다. 처음에는 느리게 떴는데, 앱을 켠 뒤 2.5초를 일부러 기다리는 코드가 있었습니다. 대기를 없앴고, 직전 확인 결과를 저장해 두었다가 앱을 켜자마자 바로 띄웁니다.

새 버전 안내 팝업 Play 스토어 없이 확인할 수 있게 앱 API를 흉내 낸 화면입니다.

7. 랭킹: Firebase

처음에는 앞서 만든 앱과 같은 Firebase 프로젝트를 같이 썼습니다. 그런데 보안 규칙이 앱마다 다르고 한쪽 규칙을 고치면 다른 쪽이 영향을 받아서, 네온 레인 전용 프로젝트로 분리했습니다. 규칙은 이렇게 잡았습니다.

  • 읽기는 누구나, 쓰기는 익명 로그인한 사용자만
  • 본인 행만, 더 높은 점수로만 갱신
  • 점수는 서버 시간으로만 기록, 삭제 불가
  • 거리에 비해 비현실적으로 높은 점수는 거부

한계도 있습니다. 클라이언트가 보내는 점수라서 규칙의 범위 안에서 조작된 점수까지는 막지 못합니다. 엄격하게 막으려면 서버에서 검증해야 합니다. 앱 데이터를 지우면 새 익명 계정이 되어 이전 기록과 연결되지 않는다는 점도 있습니다.

8. 광고 설계

광고는 게임을 방해하지 않는 위치에만 넣었습니다.

  • 플레이 중에는 광고가 없습니다.
  • 결과 화면 아래에 배너를 보여줍니다.
  • “다시 도전” 2번에 1번 시작 전에 전면 광고를 보여줍니다. 닫히기 전에는 게임이 시작되지 않습니다.
  • 유럽·영국 사용자에게는 동의 화면을 보여주고, 필요한 경우 설정에서 동의를 바꿀 수 있습니다.
  • 광고 등급은 전체이용가 수준으로 제한하고, 대상 연령은 13세 이상으로 설정했습니다(아동 대상 아님).

개발 중에는 Google 테스트 광고만 나오도록 하고, 스토어용 빌드에서만 실제 광고 단위가 쓰이게 분리했습니다. 개발 중에 실제 광고를 누르면 계정이 제재될 수 있기 때문입니다.

9. 출시 과정: 체크할 것이 많다

Play Console에서 한 일을 순서대로 정리하면 이렇습니다.

단계 내용
앱 만들기 이름, 언어, 게임, 무료/유료 선택(아래 참고)
앱 콘텐츠 개인정보처리방침 URL, 앱 액세스, 광고 여부, 광고 ID, 콘텐츠 등급, 대상 연령, 데이터 보안
스토어 등록정보 앱 이름, 간단한 설명, 자세한 설명, 아이콘 512, 그래픽 이미지 1024×500, 스크린샷, 카테고리와 태그, 연락처
비공개 테스트 테스터 이메일 목록 12명 이상, 14일 유지
프로덕션 액세스 신청 질문 3단계(비공개 테스트 정보 → 게임 정보 → 프로덕션 준비)
승인 후 출시 프로덕션 새 버전, 출시 노트, 검토 전송
AdMob 앱 스토어 연결, app-ads.txt 인증

꼭 알아 두면 좋은 것들

  • 무료 앱을 나중에 유료로 바꿀 수 없습니다. 앱을 만들 때 가격 유형을 정하면 유료 → 무료만 가능합니다. 유료로 팔려면 처음부터 유료 앱으로 만들거나 새 패키지로 새 앱을 만들어야 합니다.
  • 개인정보처리방침 URL이 필요합니다. 블로그(GitHub Pages)에 페이지를 만들어 URL을 입력했습니다. 닉네임, 익명 ID, 점수, 광고 ID 수집 내용을 적었습니다.
  • 데이터 보안 양식은 광고 SDK가 수집하는 항목(광고 ID, 대략적 위치, 진단 정보)까지 빠짐없이 적어야 합니다.
  • IARC 등급 메일이 갑자기 왔다고 놀라지 마세요. 콘텐츠 등급 설문을 제출하면 “IARC Live Rating Notice”가 영어로 자동 발송됩니다. 로그인이나 결제를 요구하지 않는 안내문입니다.
  • 프로덕션 액세스 신청서는 300자 제한이 있습니다. 실제 테스트에서 있었던 피드백과 수정 내역을 사실대로 쓰고, 날짜·인원 같은 숫자는 직접 확인한 값만 적었습니다.
  • AdMob 앱 인증은 app-ads.txt 파일이 필요합니다. Play 등록정보에 적은 개발자 웹사이트의 최상위 주소에 app-ads.txt가 없으면 “파일을 찾을 수 없음(HTTP 404)”이 나옵니다. 이 블로그 루트에 한 줄짜리 파일을 올려서 해결했고, 인증이 통과됐습니다.
  • “버전 코드”는 올릴 때마다 높아야 합니다. 같은 파일을 다시 올리면 오류가 나므로, 다른 트랙에 올리려면 “라이브러리에서 추가”를 씁니다.

10. 배운 점

  1. 테스터 한 명의 제보가 코드의 구멍을 드러낸다. 점수 5배 차이는 시뮬레이션으로 44배였습니다. 눈으로 보고 넘어갔다면 랭킹이 무너졌을 겁니다.
  2. “개선”도 측정해야 한다. 음질을 높인다고 만든 코드가 이전보다 4배 무거웠습니다. 느낌이 아니라 숫자로 비교하니 원인이 바로 보였습니다.
  3. 전환 연출은 게임 규칙과 맞물려야 한다. 보기에 멋있는 전환이 장애물과 겹치면 플레이어를 죽이는 함정이 됩니다.
  4. 광고는 흐름의 바깥에. 광고가 게임 안으로 들어오는 순간 리뷰가 나빠집니다.
  5. 스토어 등록은 개발만큼 일이다. 앱 콘텐츠, 데이터 보안, 광고 선언, 등급, 연령 설정이 서로 일관되어야 합니다.
  6. 개발 환경의 제약도 설계에 영향을 준다. SDK 없이 만든 첫 AAB는 광고가 필요해지면서 폐기됐습니다.

11. 다음 계획

  • 테스터와 사용자 의견을 계속 반영 (후반 화면 떨림, 음질)
  • 이벤트 종류와 곡 구성 확장
  • 랭킹 시즌제(주간·월간)와 보상 검토
  • Android vitals(비정상 종료)와 리뷰를 보면서 안정화

12. 지금 해 보세요

네온 레인 앱 아이콘

박자에 맞춰 네 개의 선을 달려 보세요. 오늘의 곡은 오늘 하루만 같은 곡입니다.

다른 앱 개발 기록은 앱개발 카테고리에서 볼 수 있습니다.