본문 바로가기
Projects

[앱인토스-게임] 전설의 무사(Legendary Slash)

by miracle-tech 2026. 2. 22.
320x100
반응형

전설의 무사 (Legendary Slash)

게이지 타이밍에 맞춰 스와이프로 오브젝트를 베는 원핸드 캐주얼 게임

스크린샷 / 데모

https://perfect-slice-master.vercel.app/

 

전설의 무사 (Legendary Slash)

타이밍 게이지에 맞춰 스와이프로 오브젝트를 베는 원핸드 캐주얼 게임

perfect-slice-master.vercel.app

 

토스 앱인토스 Webview 출시용 HTML5 게임

기술 스택

  • React 18 + TypeScript
  • Vite 5
  • Tailwind CSS 3.4
  • Canvas API (게이지 바 애니메이션)
  • Web Audio API (BGM 10티어 + 효과음, 오디오 파일 없이 코드로 합성)
  • html2canvas (수료증 이미지 캡처 및 공유)
  • @apps-in-toss/web-framework (토스 SDK — 광고, 인앱결제, 리더보드)
  • @sentry/react (에러 트래킹)

 

왜 만들었나

모바일에서 한 손으로 짧게 즐길 수 있는 게임을 만들고 싶었습니다.

"타이밍 맞춰 베기"라는 단순한 조작 하나로 100개 스테이지를 진행하는 구조를 떠올렸고, 토스 앱인토스 플랫폼이 웹뷰 기반 캐주얼 게임에 적합하다고 판단해서 개발을 시작했습니다. 복잡한 조작 없이 스와이프 한 번으로 플레이할 수 있으면서도, 스테이지가 올라갈수록 게이지 속도와 판정 범위가 바뀌어 적당한 긴장감이 생기는 게임을 목표로 했습니다.

 

주요 기능

  • 100개 스테이지 & 10개 테마 — 과일부터 우주까지, 스테이지별 이모지 오브젝트와 배경색이 변하며 점진적으로 난이도가 상승합니다. 게이지 속도는 0.8(1스테이지)에서 약 8.0(100스테이지)까지 올라가고, Perfect 판정 범위는 5%에서 1%로 줄어듭니다.
  • 스와이프 슬라이스 연출 — 실제 스와이프 방향에 따라 이모지가 두 조각으로 갈라지는 연출을 CSS clip-path 삼각함수 계산으로 구현했습니다. PERFECT/GOOD/MISS 판정에 따라 파티클 수, 분리 거리, 이펙트 색상이 달라집니다.
  • 무기 상점 (16종) — 코인으로 구매하는 15종 일반 무기와 인앱결제 프리미엄 무기 "신의 손"이 있습니다. 무기마다 정확도 보너스(+0.2%~+3.0%)가 적용되어 판정 범위가 넓어집니다.
  • 콤보 & 점수 시스템 — 연속 성공 시 콤보가 쌓이며 3콤보부터 x2, 5콤보 x3, 10콤보 x5 배수가 적용됩니다. 재도전 시에는 코인 보상이 50%로 줄어 코인 파밍을 방지합니다.
  • 하트 시스템 — 일일 5개 하트가 자정에 리필됩니다. MISS 시 하트가 소진되고, 0개가 되면 게임오버입니다. 보상형 광고를 시청하면 하트를 충전할 수 있습니다.
  • 코드 합성 BGM — Web Audio API로 오디오 파일 없이 BGM을 실시간 생성합니다. 스테이지 구간별 10개 티어(100~178 BPM)로 구성되며, 킥/스네어/하이햇/샤미센 등 드럼과 멜로디를 오실레이터로 합성합니다.
  • 오브젝트 이동 패턴 (41스테이지+) — 좌우, 상하, 원형, 대각선, 8자, 포물선, 지그재그, 진자 등 8종 움직임 패턴이 적용되어 스와이프 정확도에 도전을 더합니다.
  • 엔딩 수료증 — 100스테이지 클리어 시 클리어 통계가 담긴 수료증을 html2canvas로 이미지 캡처하여 공유할 수 있습니다.
  • 한국어/영어 다국어 지원 — 브라우저 언어를 자동 감지하고 설정에서 수동 전환할 수 있습니다. UI 문자열 55개와 게임 데이터(스테이지명 100개, 무기 16개) 전체를 번역했습니다.
  • 리더보드 — 토스 게임센터 리더보드에 누적 최고 점수를 제출합니다.

 

배운 점

  • Web Audio API 프로시저럴 사운드 합성 — 오실레이터 타입(triangle, square, sawtooth)과 주파수 스윕, 노이즈 생성을 조합해 킥 드럼(150Hz→60Hz 스윕), 스네어(200Hz + 화이트노이즈), 하이햇(7000Hz 하이패스 노이즈) 등을 코드만으로 만드는 방법을 배웠습니다. 오디오 파일 없이 10티어 BGM과 모든 효과음을 구현하니 번들 사이즈가 크게 줄었습니다.
  • CSS clip-path 삼각함수 분할 — 스와이프 각도(atan2)를 기반으로 cos/sin 값을 polygon 좌표에 적용해 이모지를 실제 베는 방향대로 두 조각으로 나누는 기법을 익혔습니다.
  • Canvas API 실시간 게이지 렌더링 — requestAnimationFrame 루프에서 roundRect, arc, fillText 등으로 게이지 바, 포인터, 판정 영역, 진행 도트를 매 프레임 그리는 패턴을 적용했습니다.
  • Context 기반 경량 i18n 구현 — react-i18next 없이 React Context + {{변수}} 치환 방식으로 약 5KB 수준의 다국어 시스템을 직접 구현했습니다. UI 문자열과 게임 데이터(스테이지명, 무기 정보)를 분리하고, 브라우저 언어 자동 감지 + localStorage 저장 전략을 설계했습니다.
  • 토스 플랫폼 추상화 — 광고(GoogleAdMob), 인앱결제, 리더보드 API를 isInToss() 분기로 감싸 로컬 개발 환경에서는 모의 UI를, 토스 앱 안에서는 실제 SDK를 호출하는 듀얼 모드 구조를 만들었습니다.

 

어려웠던 점

  • Chrome AudioContext 자동재생 정책 대응 — 사용자 제스처 없이 AudioContext를 생성하면 suspended 상태로 시작되어 소리가 나지 않는 문제가 있었습니다. AudioContext를 싱글톤으로 관리하면서, 첫 터치/클릭 이벤트에서 resume()을 호출하는 지연 초기화 패턴으로 해결했습니다. BGM 엔진이 suspended 상태를 감지하면 재시도하는 상태 머신도 추가했습니다.
  • 하트 리셋 타임존 버그 — UTC 기준 날짜 비교를 사용했더니 한국(UTC+9) 사용자의 하트가 오전 9시에 리셋되는 문제가 발생했습니다. heartDate를 로컬 타임존 기준 YYYY-MM-DD 문자열로 저장하도록 수정하여 자정에 정확히 리필되게 했습니다.
  • passive 이벤트 리스너 경고 — 터치 이벤트에서 e.preventDefault()를 호출하면서 passive 리스너 위반 경고가 뜨는 문제가 있었습니다. 게임 영역의 touchstart/touchend/touchmove에 { passive: false }를 명시적으로 지정하여 스크롤/pull-to-refresh를 막으면서 경고를 제거했습니다.
  • 슬라이스 이펙트와 게임 루프 동기화 — 스와이프 → 칼날 이동 → 오브젝트 분할 → 결과 표시 → 다음 라운드까지의 애니메이션 시퀀스가 5단계 Phase 상태 머신(swing → slash → split → text → fadeout → done)으로 관리되는데, 각 단계의 타이밍을 게임 상태 업데이트와 맞추는 것이 까다로웠습니다. slashData 상태와 handleSlashComplete 콜백으로 애니메이션 완료 후에만 점수/콤보가 반영되도록 분리했습니다.

 

링크

  • GitHub: (비공개)
  • 서비스: 구글 play store 등록중

 

다음 계획

  • 토스 개발자센터에서 실제 광고 그룹 ID를 발급받아 보상형 광고 연동 완료하기
  • 인앱결제 서버 사이드 영수증 검증 구현하기
  • 스테이지 41+ 이동 패턴 추가 및 보스 스테이지 기획
  • 성능 최적화: 사용하지 않는 Radix UI/shadcn 의존성 제거로 번들 사이즈 경량화
320x100