
[simsim-arcade 팀 프로젝트 발표]
심심오락실(Simsim Arcade) 은 웹 브라우저에서 다양한 아케이드 게임을 즐길 수 있도록 개발한 웹사이트입니다.
단순히 게임을 실행하는 것에서 끝나는 것이 아니라, 각 게임의 고유한 플레이 방식과 조작감, 점수 시스템, 랭킹 연동, 데이터 저장, 시각적 효과까지 고려하여 구현했습니다.
이번에 담당한 콘텐츠는 총 4종입니다.
각 콘텐츠의 기능뿐만 아니라, 실제로 어떤 기술을 사용해 구현했는지 중심으로 정리했습니다.
프로젝트는 프론트엔드, 백엔드, 데이터베이스를 분리한 구조로 구성했습니다.
| 구분 | 사용 기술 | 역할 |
|---|---|---|
| 프론트엔드 | React | 메뉴, 설정, 결과 화면 등 UI 구성 |
| 언어 | TypeScript | 게임 및 애플리케이션 코드 작성과 타입 관리 |
| 빌드 도구 | Vite | 프론트엔드 개발 및 빌드 |
| 화면 이동 | React Router | 게임별 경로 관리 |
| 그래픽 | HTML5 Canvas 2D | 캐릭터, 배경, 이펙트, 탄막 등을 직접 렌더링 |
| 애니메이션 | requestAnimationFrame | 게임 루프와 화면 갱신 |
| 사운드 | Web Audio API | 효과음과 배경음악 실시간 합성 |
| 백엔드 | Cloudflare Workers + Hono | 점수 등록 및 랭킹 조회 API |
| 데이터베이스 | Cloudflare D1(SQLite) | 게임 정보 및 점수 기록 저장 |
| ORM | Drizzle ORM | 데이터베이스 스키마 및 쿼리 관리 |
| 유효성 검사 | Zod | API 요청 데이터 검증 |
| 패키지 관리 | pnpm workspace | 모노레포 및 패키지 관리 |
| 배포 | Cloudflare Pages + Workers | 웹사이트 및 API 배포 |
공통 타입은 별도의 packages/shared 패키지에서 관리합니다.
프론트엔드와 백엔드가 같은 타입 정의를 사용하므로, 요청과 응답 데이터의 구조를 일관되게 유지할 수 있습니다.
게임마다 조작 방식과 규칙은 다르지만, 게임을 실행하고 점수를 등록하는 과정에는 공통점이 많습니다.
이를 해결하기 위해 게임별 코드는 독립적으로 관리하고, 공통 실행 구조와 점수 등록 API는 재사용하도록 설계했습니다.
게임을 새로 추가할 때 기본적으로 수정하는 위치는 다음과 같습니다.
apps/web/src/games/<게임id>/ — 게임 컴포넌트, 엔진, 그래픽, 사운드apps/web/src/games/registry.ts — 게임 등록 및 지연 로딩 설정packages/shared/src/game.ts — 게임별 점수 상한 설정apps/api/seeds/<게임id>.sql — 데이터베이스 게임 정보 등록이 구조를 사용하면 게임마다 별도의 라우트와 점수 API를 새로 구현하지 않아도 됩니다.
메인 화면의 게임 카드와 /games/:gameId 경로도 등록 정보를 바탕으로 연결됩니다.
일반적인 웹 화면은 React 상태가 변경되면 필요한 부분을 다시 렌더링합니다.
하지만 게임에서는 캐릭터, 탄환, 파티클 등 수많은 객체가 초당 여러 번 움직입니다. 이런 객체의 움직임을 모두 React 상태로 관리하면 불필요한 렌더링 비용이 커질 수 있습니다.
따라서 다음과 같이 역할을 분리했습니다.
게임은 requestAnimationFrame을 이용해 별도의 루프에서 동작합니다.
이를 통해 게임의 실시간 처리와 일반적인 UI 렌더링을 분리했습니다.
게임 목록에는 React의 lazy()를 적용했습니다.
모든 게임의 코드를 초기 화면에서 한꺼번에 불러오는 대신, 사용자가 특정 게임에 진입할 때 해당 게임의 코드를 불러옵니다.
게임별 코드가 별도의 청크로 나뉘므로 초기 화면에서 불필요하게 다운로드하는 코드를 줄일 수 있습니다.
게임 컴포넌트는 공통 GameProps 타입을 사용하며, 핵심적으로 onFinish(score) 콜백을 전달받습니다.
게임이 종료되면 최종 점수를 전달하고, 공통 게임 페이지에서 결과창과 점수 등록 절차를 처리합니다.
다시 하기를 선택하면 round 값을 변경해 게임 컴포넌트를 새로 마운트하므로 이전 게임의 상태가 남지 않도록 했습니다.
또한 ErrorBoundary를 적용해 게임 내부에서 오류가 발생하더라도 페이지 전체가 중단되는 문제를 방지하도록 구성했습니다.
과일 슬라이서는 화면에 날아오는 과일을 마우스나 손가락으로 그어 베는 게임입니다.
과일을 놓치면 목숨이 감소하고, 폭탄을 베면 즉시 게임 오버가 됩니다.
주요 기능은 다음과 같습니다.
과일 하나를 베면 10점을 얻습니다.
연속으로 과일을 베면 콤보가 증가하고, 콤보가 10단위에 도달할 때마다 추가 점수를 지급합니다.
예를 들어 20콤보에 도달하면 다음과 같이 계산됩니다.
20 × 5 = 100점
피버 타임 중에는 과일 점수가 두 배가 되며, 피버 타임은 과일 20개를 놓치지 않고 연속으로 베었을 때 발동합니다.
피버 타임은 10초 동안 지속되며 다음과 같은 변화가 적용됩니다.
과일 슬라이서에서 가장 중요한 부분은 사용자가 과일을 실제로 베었는지 판단하는 것입니다.
단순히 마우스 포인터가 과일 위에 있는지만 검사하면 빠르게 마우스를 움직였을 때 과일을 통과해 버리는 문제가 발생할 수 있습니다.
이를 해결하기 위해 마우스가 한 프레임 동안 이동한 경로를 선분으로 취급했습니다.
이 선분과 과일 중심 사이의 최단거리를 계산하고, 해당 거리가 과일의 판정 반경 안에 들어오면 과일을 벤 것으로 처리합니다.
즉, 특정 순간의 포인터 위치만 확인하는 것이 아니라 포인터가 이동한 경로 전체를 기준으로 판정하는 방식입니다.
또한 getCoalescedEvents()를 이용해 브라우저에서 합쳐진 입력 이벤트의 중간 좌표까지 활용합니다.
이렇게 하면 빠르게 그어도 입력 궤적이 누락되어 과일을 놓치는 문제를 줄일 수 있습니다.
마우스, 터치, 펜 입력을 각각 별도로 구현하지 않고 Pointer Events를 사용해 통합했습니다.
setPointerCapture()를 활용해 포인터가 움직이는 동안 입력을 안정적으로 추적할 수 있도록 구성했습니다.
이를 통해 PC와 모바일에서 동일한 게임 로직을 활용할 수 있습니다.
과일은 중력의 영향을 받는 포물선 운동으로 움직입니다.
먼저 과일이 도달할 목표 높이를 정한 다음, 해당 높이에 도달하기 위한 초기 속도를 계산합니다.
또한 과일이 서로 겹쳐서 발사되는 상황을 줄이기 위해 여러 개의 발사 궤적을 후보로 생성하고, 이미 날아가고 있는 과일들과 가장 덜 겹치는 궤적을 선택합니다.
폭탄과 과일 사이에도 충분한 간격을 두어 플레이어가 대응하기 어려운 상황을 줄였습니다.
게임 진행 기록은 브라우저의 localStorage에 저장합니다.
누적 슬라이스 수, 최고 콤보, 피버 타임 횟수, 최고 점수 등 다양한 기록을 바탕으로 퀘스트를 달성할 수 있습니다.
퀘스트를 완료하면 새로운 검과 배경 테마가 해금됩니다.
저장된 값이 손상된 경우에도 기본값을 사용하도록 처리해 데이터 문제로 게임이 중단되는 상황을 줄였습니다.
과일 슬라이서는 다른 두 게임과 달리 게임 내부에서 직접 닉네임 입력과 TOP 5 랭킹 화면을 제공합니다.
공통 API 클라이언트를 이용해 점수를 등록하고 랭킹을 조회하므로 백엔드 코드를 별도로 추가하지 않았습니다.
특히 서버 랭킹 TOP 3에 해당하는 닉네임이 확인되면 사용할 수 있는 특별 검인 '여명의 검'을 구현했습니다.
로컬 퀘스트와 달리 실제 서버 랭킹을 확인해 사용할 수 있는 보상이라는 점에서 프론트엔드와 백엔드의 연동 사례가 됩니다.
스카이 에이스는 비행기를 조종해 적의 공격을 피하고 보스를 격파하는 종스크롤 탄막 슈팅 게임입니다.
총 5개의 스테이지로 구성되며, 각 스테이지에는 2단계로 변신하는 보스가 등장합니다.
주요 기능은 다음과 같습니다.
| 기체 | 특징 | 필살기 |
|---|---|---|
| P-38 라이트닝 | 밸런스형, 지원 드론 | 폭격기 편대의 융단 폭격 |
| 신덴 | 화력형, 관통 공격 | 적탄을 빨아들이는 에너지 회오리 |
| 스핏파이어 | 빠른 연사와 유도 미사일 | 시간 정지와 환영 칼날 |
| XF-0 피닉스 | 숨겨진 강화 기체 | 불사조 강림 |
숨겨진 기체인 XF-0 피닉스는 홈 화면의 'SKY ACE' 제목을 누르면 발견할 수 있도록 구현했습니다.
게임의 움직임이 모니터의 주사율에 따라 달라지는 문제를 줄이기 위해 고정 시간 간격 방식을 적용했습니다.
모니터는 초당 60회, 120회, 144회 등 서로 다른 횟수로 화면을 갱신할 수 있습니다.
게임 로직이 화면 갱신 횟수에만 의존하면 사용하는 기기에 따라 게임 속도가 달라질 수 있습니다.
이를 해결하기 위해 requestAnimationFrame으로 실제 프레임을 받아오되, 경과 시간을 누적해 게임 로직을 1/60초 단위로 처리하도록 구현했습니다.
한 프레임에서 처리하는 시뮬레이션 횟수는 최대 5회로 제한했습니다.
이를 통해 화면 갱신 속도와 게임 진행 속도를 분리하고, 일시적인 지연이 발생했을 때 계산이 과도하게 몰리는 문제도 줄였습니다.
탄막 슈팅 게임에서는 많은 탄환이 동시에 화면에 나타납니다.
모든 탄환을 복잡하게 검사하면 연산량이 증가할 수 있으므로 충돌 판정을 효율적으로 구성하는 것이 중요합니다.
스카이 에이스는 플레이어의 실제 피격 판정 반경을 4픽셀로 작게 설정했습니다.
화면에 보이는 비행기 전체가 아니라 중앙의 작은 영역을 피격 판정으로 사용하기 때문에, 탄환이 비행기의 외형에 닿았더라도 실제 판정 영역을 벗어나면 피격되지 않을 수 있습니다.
또한 원과 원 사이의 거리를 비교할 때 제곱근을 계산하지 않고 제곱된 거리끼리 비교하도록 구현했습니다.
이 방식을 사용하면 다수의 탄환에 대한 충돌 판정에서 불필요한 연산을 줄일 수 있습니다.
스테이지의 적 편대는 코드에 직접 반복해서 작성하는 대신 설정 데이터로 관리합니다.
예를 들어 특정 시간에 어떤 적 편대가 어느 위치에서 등장할지 config.ts에 정의하고, StageManager가 해당 데이터를 읽어 게임 진행을 제어합니다.
스테이지 진행은 다음과 같은 순서로 구성됩니다.
waves → warning → boss → clear
이렇게 게임 로직과 스테이지 데이터를 분리하면 새로운 스테이지를 추가할 때 기존 엔진을 크게 변경하지 않고도 등장 시간, 적 종류, 배치 등을 조정할 수 있습니다.
보스마다 서로 다른 공격 패턴을 구현했습니다.
보스의 체력이 절반 이하로 떨어지면 2단계로 변신하며 공격 패턴이 달라집니다.
점수는 생존 시간, 적 격추, 보스 변신, 보스 격파, 남은 목숨과 필살기, 전체 스테이지 클리어 등을 반영해 계산합니다.
게임 종료 시에는 결과 요약 화면을 보여 준 뒤 onFinish(score)를 호출해 공통 점수 등록 시스템으로 연결합니다.
캣 블레이드는 고양이 캐릭터를 조작해 적을 처치하고 보스를 격파하는 횡스크롤 액션 게임입니다.
핵심 재미는 단순한 공격보다 적의 공격을 읽고, 타이밍에 맞춰 패링하거나 무적 구르기로 회피하는 전투에 있습니다.
주요 기능은 다음과 같습니다.
| 폼 | 전투 특징 |
|---|---|
| 닌자 캣 | 빠른 연속 베기 |
| 나이트 캣 | 방어와 패링 |
| 파이어 캣 | 화염 검기와 범위 공격 |
| 치즈 냥이 | 강력한 타격과 지면 파쇄 |
| 사이버 캣 | 레이저 기반 원거리 공격 |
각 폼은 이동 속도, 점프력, 패링 가능 시간, 받는 피해 등이 서로 다릅니다.
또한 스킬 쿨다운을 폼마다 독립적으로 관리하도록 구현했습니다.
따라서 한 폼의 스킬을 사용한 뒤 다른 폼으로 전환해 다른 스킬을 이어 사용하는 전략이 가능합니다.
패링은 적의 공격에 맞춰 타이밍을 맞추면 공격을 받아치는 기능입니다.
패링에 성공하면 반격 피해를 주고, 투사체나 충격파는 적에게 되돌려 보낼 수 있습니다.
성공 순간에는 다음과 같은 시각적 효과가 적용됩니다.
이러한 연출은 공격 성공 여부를 즉시 전달하고, 전투의 타격감을 강화하기 위한 것입니다.
무적 구르기는 레이저나 바닥 공격 표시처럼 패링만으로 대응하기 어려운 공격을 회피할 때 사용할 수 있습니다.
적의 공격은 다음 순서로 진행됩니다.
예고(Windup) → 공격 → 회복
공격 전에 노란색 시각 효과를 보여 주어 플레이어가 공격을 예측할 수 있도록 구성했습니다.
특히 예고 공격을 패링하면 적이 더 크게 휘청이도록 구현해, 공격 패턴을 읽고 대응하는 플레이를 유도했습니다.
보스에게는 별도의 패링 게이지가 있습니다.
패링에 성공할 때마다 게이지가 증가하고, 100에 도달하면 보스가 BREAK 상태가 됩니다. 보스는 약 2.2초 동안 기절하고, 이 시간 동안 받는 피해가 증가합니다.
따라서 플레이어는 단순히 공격을 피하는 것뿐만 아니라 패링을 활용해 공격 기회를 만들어야 합니다.
캣 블레이드의 기술적인 핵심 중 하나는 JavaScript의 제너레이터 함수인 function*를 활용한 보스 패턴입니다.
제너레이터는 실행 도중 yield를 만나면 잠시 멈췄다가 나중에 이어서 실행할 수 있는 함수입니다.
예를 들어 보스가 공격을 예고하고, 0.5초 기다린 뒤 돌진하고, 착지한 뒤 회복하는 패턴을 순서대로 작성할 수 있습니다.
개념적으로는 다음과 같습니다.
function* bossAttack() {
yield 0.5; // 0.5초 대기
// 공격 실행
yield 0; // 다음 프레임까지 대기
// 착지 및 회복
}
위 코드는 제너레이터의 사용 개념을 보여 주기 위한 간단한 예시입니다.
실제 게임에서는 보스 패턴의 각 단계와 대기 시간을 관리하고, 기절하면 진행 중인 제너레이터를 취소한 뒤 다음 패턴을 시작하도록 구성했습니다.
이 방식은 공격 순서를 코드에서 위에서 아래로 읽을 수 있다는 장점이 있습니다.
또한 보스는 공통 Boss 클래스를 기반으로 구현하고, 각 보스가 자신만의 공격 패턴을 가지도록 구성했습니다.
메뉴에서 고양이 카드를 짧은 시간 안에 두 번 누르면 해당 고양이의 각성 폼으로 시작할 수 있습니다.
각성 폼은 최대 체력과 공격력, 이동 및 전투 능력이 강화되며 결과창에도 각성 폼 이름이 표시됩니다.
단순히 숨겨진 캐릭터를 추가하는 데서 끝나지 않고, 기존 캐릭터 시스템을 활용해 강화된 플레이 경험을 제공하도록 구현했습니다.
돌림판 룰렛은 인터넷 방송에서 벌칙, 미션, 후원 이벤트 등을 추첨하기 위한 도구입니다.
주요 기능은 다음과 같습니다.
각 항목은 가중치를 설정할 수 있습니다.
예를 들어 벌칙*3이라고 입력하면 해당 항목의 가중치는 3이 됩니다.
다른 항목들의 가중치가 모두 1이라고 가정하면, 전체 가중치 합을 기준으로 각 항목의 추첨 확률이 계산됩니다.
가중치가 높을수록 당첨될 확률이 높아지고, 돌림판에서도 더 큰 영역을 차지합니다.
또한 뽑힌 항목을 다음 추첨에서 제외하는 모드를 지원합니다. 가중치가 3인 항목이 선택되면 가중치를 2로 줄이는 방식이며, 제외된 항목은 다시 되돌릴 수 있습니다.
룰렛에서 가장 중요한 구현 원칙은 당첨 항목을 먼저 선택하고, 애니메이션은 해당 결과를 보여 주는 역할만 하도록 구성하는 것입니다.
추첨 과정은 다음과 같습니다.
crypto.getRandomValues()를 이용해 난수를 생성하고 가중치에 따라 당첨 항목을 선택합니다.따라서 애니메이션이 어느 위치에서 멈췄는지를 보고 당첨 항목을 결정하는 것이 아닙니다.
이미 추첨된 결과를 기준으로 회전 각도를 계산하므로, 아슬아슬하게 멈추는 연출을 추가해도 당첨 항목 자체는 바뀌지 않습니다.
다만 추첨 로직은 브라우저에서 실행되므로, 이 설계가 외부의 악의적인 조작까지 서버 수준으로 방지한다는 의미는 아닙니다.
돌림판은 처음에는 빠르게 회전하고, 끝으로 갈수록 천천히 멈추도록 구현했습니다.
감속 함수는 다음과 같습니다.
easeOut(t) = 1 - (1 - t) ** 4
이 함수를 활용하면 회전 후반부에서 속도가 점차 줄어들어 칸 경계를 하나씩 넘어가는 느낌을 만들 수 있습니다.
바늘 아래에 있는 항목이 바뀔 때는 Web Audio API로 효과음을 재생하고, 바늘이 튕기는 애니메이션도 적용했습니다.
또한 전체 화면과 고해상도 화면에서도 선명하게 보이도록 devicePixelRatio와 ResizeObserver를 활용했습니다.
돌림판은 일반 게임과 달리 점수나 랭킹을 저장할 필요가 없습니다.
따라서 별도의 백엔드 API나 데이터베이스를 사용하지 않고 브라우저 안에서 독립적으로 실행되도록 구현했습니다.
사용자가 입력한 항목만 localStorage에 저장해 다음에도 다시 사용할 수 있도록 구성했습니다.
이는 모든 기능에 무조건 서버를 도입하는 것이 아니라, 기능의 목적과 데이터 특성에 맞춰 필요한 기술을 선택한 사례입니다.
과일 슬라이서, 스카이 에이스, 캣 블레이드는 공통 점수 API를 이용해 점수를 등록하거나 랭킹을 조회할 수 있습니다.
| API | 기능 |
|---|---|
POST /api/games/:gameId/scores | 점수 등록 |
GET /api/games/:gameId/ranking?limit=N | 게임별 상위 점수 조회 |
GET /api/games/:gameId/questions | 퀴즈용 문제 조회 |
이번에 담당한 아케이드 게임 3종은 문제 조회 API를 사용하지 않습니다.
점수 등록 API에는 Zod 기반 검증을 적용했습니다.
점수 상한은 게임 내부 설정과 서버의 MAX_SCORE_BY_GAME에 함께 정의해 클라이언트와 서버에서 각각 검증할 수 있도록 구성했습니다.
다만 현재는 클라이언트에서 계산한 점수를 전달하므로 상한 범위 내의 점수 조작까지 완전히 막을 수는 없습니다. 이를 보완하려면 추가적인 플레이 기록 검증과 부정 이용 방지 기능이 필요합니다.
동점인 경우에는 먼저 등록한 기록을 우선합니다.
랭킹 조회에서는 다음 정렬 기준을 사용합니다.
ORDER BY score DESC, id ASC
점수를 내림차순으로 정렬하고, 점수가 같으면 기록 ID가 작은 순서로 표시합니다.
| 저장 대상 | 저장 위치 |
|---|---|
| 게임 정보 | Cloudflare D1 |
| 점수 기록 | Cloudflare D1 |
| 개인별 해금 정보 | localStorage |
| 퀘스트 진행 기록 | localStorage |
| 게임 설정 및 음량 | localStorage |
| 룰렛 항목 | localStorage |
여러 사용자에게 공유되어야 하는 데이터는 서버에 저장하고, 특정 브라우저에서 유지하면 되는 설정과 진행 기록은 로컬에 저장하도록 구분했습니다.
| 게임 | 핵심 구현 기술 | 주요 목적 |
|---|---|---|
| 과일 슬라이서 | 선분과 원 사이 거리 계산 | 빠른 마우스·터치 입력에서도 정확한 슬라이스 판정 |
| 과일 슬라이서 | getCoalescedEvents() | 입력 궤적의 중간 좌표 활용 |
| 과일 슬라이서 | 포물선 운동 및 궤적 선택 | 자연스러운 과일 움직임과 겹침 감소 |
| 스카이 에이스 | Fixed Timestep | 모니터 주사율에 따른 게임 속도 차이 감소 |
| 스카이 에이스 | 제곱 거리 비교 | 다수의 탄환 충돌 판정 효율화 |
| 스카이 에이스 | 데이터 기반 스테이지 | 적 편대와 등장 시점의 유연한 관리 |
| 캣 블레이드 | 패링 및 전투 상태 관리 | 타이밍 중심의 전투 시스템 |
| 캣 블레이드 | 제너레이터 함수 | 시간 순서가 있는 보스 패턴 구현 |
| 캣 블레이드 | 히트스톱과 카메라 효과 | 공격 성공 순간의 타격감 강화 |
| 돌림판 룰렛 | 암호학적 난수와 가중치 계산 | 가중치 기반 추첨 |
| 돌림판 룰렛 | 목표 회전 각도 계산 | 추첨 결과와 애니메이션 분리 |
| 돌림판 룰렛 | Web Audio API | 효과음과 팡파레 생성 |
이번 프로젝트에서 중요하게 생각한 부분은 단순히 게임을 구현하는 것을 넘어, 각 기능을 안정적으로 연결하고 유지보수하기 쉬운 구조로 설계하는 것이었습니다.
게임마다 조작 방식과 규칙은 다르지만, 게임 실행과 점수 등록, 랭킹 조회 등은 공통으로 사용할 수 있습니다.
이 기능들을 분리해 두면 게임을 추가할 때 반복 구현을 줄이고 기존 시스템을 재사용할 수 있습니다.
게임에서는 많은 객체가 지속적으로 움직이기 때문에 렌더링과 게임 로직을 분리하는 것이 중요합니다.
Canvas와 별도 엔진을 활용하고, 고정 시간 간격 방식과 충돌 판정 최적화를 적용하면서 게임의 움직임과 연산량을 함께 고려했습니다.
콤보와 피버 타임, 각성 폼, 숨겨진 기체, 보스의 공격 예고와 패링 연출은 단순한 기능 추가가 아닙니다.
사용자가 게임을 플레이하면서 목표를 발견하고, 성공 여부를 즉시 확인하며, 반복해서 도전할 수 있도록 설계한 요소들입니다.
점수와 랭킹은 서버에서 관리하고, 개인 설정과 퀘스트 기록은 브라우저에 저장했습니다.
돌림판처럼 서버 저장이 필요하지 않은 기능은 브라우저에서 독립적으로 실행하도록 구성했습니다.
이처럼 기술을 많이 사용하는 것보다 기능의 목적에 맞는 구조를 선택하는 것이 중요하다는 점을 배웠습니다.
현재의 점수 검증은 기본적인 유효성 검사와 게임별 점수 상한에 기반합니다.
실제 서비스의 신뢰도를 더 높이려면 클라이언트 점수 조작을 방지할 수 있는 추가 검증 체계를 고려해야 합니다.
또한 게임별 플레이 기록과 사용자 경험을 분석해 난이도, 보상 조건, 조작 편의성을 지속적으로 개선할 수 있습니다.
심심오락실 프로젝트에서는 과일 슬라이서, 스카이 에이스, 캣 블레이드라는 세 가지 아케이드 게임과 방송용 돌림판 룰렛을 구현했습니다.
각 콘텐츠는 서로 다른 플레이 방식을 제공하지만, 게임 실행과 점수 등록 등 공통 기능은 재사용할 수 있도록 설계했습니다.
과일 슬라이서에서는 정밀한 입력 판정과 성장 시스템을, 스카이 에이스에서는 고정 시간 간격과 탄막 처리, 데이터 기반 스테이지를, 캣 블레이드에서는 패링과 제너레이터 기반 보스 AI를 구현했습니다.
돌림판 룰렛에서는 가중치 기반 추첨과 애니메이션을 분리하고, 별도의 서버 없이 브라우저 안에서 동작하도록 구성했습니다.
이번 프로젝트를 통해 게임 개발은 캐릭터를 움직이게 만드는 것뿐만 아니라 입력 처리, 시간 관리, 충돌 판정, 데이터 저장, API 연동, 사용자 경험까지 함께 고려해야 한다는 점을 배웠습니다.
앞으로도 기존 구조를 개선하고 기능을 확장하면서, 사용성과 유지보수성을 함께 고려한 웹 애플리케이션을 개발하고자 합니다.
감사합니다.