그냥 게임 하나 만들어보고 싶었다.
AI 에이전트로 뭔가를 만들 때 "이걸 진짜로 쓸 수 있는 서비스로 만들면 어떨까?" 하는 생각이 자꾸 드는데, 게임이 그나마 결과물이 눈에 바로 보이고 재미도 있을 것 같았다. 그래서 선택한 게 테트리스였다.
클래식하고, 규칙은 단순하고, 그런데 제대로 만들려면 생각보다 할 게 엄청 많다.
1단계 — 일단 굴러가게 만들기
처음 목표는 딱 하나였다. 화면에서 블록이 떨어지게 하기.
게임 엔진 로직은 생각보다 고려할 게 많았다. 피스 회전, 벽 충돌, 라인 클리어, 레벨업에 따른 속도 변화. 각각은 단순해 보이는데 조합하면 예외 케이스가 계속 나온다. 회전할 때 벽에 걸리면 어떻게 할 건지 (wall kick), 바닥에 닿은 뒤 잠깐의 여유를 줄 건지 (lock delay) 같은 것들.
이걸 useGameEngine.ts 하나에 다 넣었는데, 지금 생각하면 그 파일이 제일 복잡한 파일이다.
게임이 돌아가니까 다음은 점수를 저장하고 싶었다. Railway PostgreSQL + Prisma로 DB를 연결하고, 플레이 끝나면 점수가 서버에 남도록 했다. 그 순간부터 이 프로젝트가 "그냥 데모"가 아니라 진짜 서비스가 된 것 같았다.
2단계 — 혼자 하는 게 아니라 같이 하는 게임으로
점수가 DB에 쌓이니까 자연스럽게 리더보드를 만들고 싶어졌다.
TOP 10 점수를 보여주는 페이지를 만들었다. 순위, 닉네임, 점수, 날짜. 단순한 구성인데 막상 내 이름이 거기 뜨니까 묘하게 기분이 좋았다.
그다음은 도전과제 시스템. "처음 1만 점 달성", "라인 100줄 클리어", "연속 테트리스 3회" 같은 것들. 이건 단순히 수치 체크가 아니라 게임 플레이 중 실시간으로 감지해야 해서 게임 엔진과 연동이 필요했다. 달성하면 토스트로 알림이 뜨고, DB에도 저장된다.
이 두 기능을 만들고 나서 처음으로 "오래 하고 싶은 게임"이 된 것 같았다.
3단계 — 꾸미는 재미
도전과제를 달성하면 뭔가 보상이 있어야 할 것 같았다. 그래서 상점을 만들었다.
처음엔 스킨 18개 정도로 시작했다. 블록 색상, 배경, 프로필 아이콘. 그러다가 칭호 시스템을 붙였다. 리더보드에 이름 옆에 칭호가 뜨는 것. 도전과제를 달성해야 얻을 수 있는 것들이라서 리더보드가 단순 점수 순위판이 아니라 "이 사람 어떤 플레이어인지" 보여주는 공간이 됐다.
코인 시스템도 생겼다. 게임을 하면 코인이 쌓이고, 코인으로 상점 아이템을 살 수 있다. 광고 시청으로 아이템을 해금하는 기능도 넣었는데, 실제 광고 SDK 연동은 아직이라 지금은 막아뒀다.
결국 상점 아이템이 40개가 넘어버렸다. 스킨, 배경, 아이콘, 칭호, 라인 클리어 이펙트까지. 처음엔 그냥 블록 색 바꾸는 정도였는데.
4단계 — 폰에서도 돼야 한다
데스크탑에서만 되는 게임을 만들 생각은 없었다. 그런데 모바일 지원이 생각보다 훨씬 손이 많이 갔다.
캔버스 크기를 화면에 맞게 조절하는 건 기본이고, 터치 컨트롤을 따로 만들어야 했다. 좌우 이동, 회전, 소프트 드롭, 하드 드롭을 화면 버튼으로. 키보드가 없으니까 버튼 배치가 직관적이어야 하고, 잘못 눌리면 안 되고.
게임오버 모달이 모바일에서 화면을 벗어나는 버그도 있었다. 스크롤이 안 되는 레이아웃이었는데, 통계가 길어지면 버튼이 화면 밖으로 나가버리는 것. 이런 건 실제로 폰으로 해봐야 발견된다.
5단계 — 작은 것들이 게임을 게임답게 만든다
기능을 다 넣고 나면 마무리 작업이 남는다. 근데 이게 생각보다 중요하다.
파티클 이펙트. 라인을 클리어할 때 파티클이 터지는 효과. 없어도 게임은 되는데, 있으면 "클리어했다"는 느낌이 확 달라진다. 캔버스 위에 파티클 레이어를 별도로 올리고, 라인 클리어 이벤트를 받아서 터지게 했다.
썸네일 애니메이션. 메인 페이지 게임 카드에 테트리스 보드가 살아 움직이는 미니 애니메이션을 넣었다. 처음엔 CSS로 단순하게 만들었다가, 피스가 실제로 떨어지고 라인이 클리어되는 시뮬레이션으로 발전시켰다. 그러다가 너무 복잡해져서 다시 단순화했다. 이 과정에서 커밋이 네 번이나 났다.
설정 저장 방식. 설정 페이지에서 바꿀 때마다 즉시 저장되면 실수로 건드렸을 때 되돌리기 어렵다. 그래서 저장 버튼을 누를 때만 DB에 반영되도록 draft 상태를 따로 관리했다.
만들고 나서
처음에 "테트리스 하나 만들어봐야지" 했을 때와 지금 완성된 걸 보면, 솔직히 이 정도까지 될 줄 몰랐다.
게임 로직, DB 연동, 인증, 리더보드, 도전과제, 상점, 코인, 칭호, 파티클, 모바일 지원, 썸네일 애니메이션까지. 커밋 수를 세어봤더니 테트리스 관련 커밋만 30개가 넘는다.
AI 에이전트와 함께 만들었는데, 이 방식이 신기한 게 내가 결정하고 AI가 구현하는 흐름이 생각보다 빠르고 재미있다. 아이디어를 말하면 코드가 나오고, 문제가 생기면 같이 디버깅하고. 혼자였으면 중간에 포기했을 것 같은 기능들이 붙었다.
물론 버그도 많았다. 게임오버 이후 이전 게임 데이터가 남아있는 버그, 설정이 저장 전에 반영되는 버그, 모바일에서 모달이 잘리는 버그. 한 번에 6~7건씩 수정하는 날도 있었다.
그래도 지금 플레이해보면 꽤 그럴듯하다. 리더보드에 이름이 남고, 칭호가 생기고, 블록 색을 바꿀 수 있고, 폰에서도 된다.
다음엔 뭘 만들지 생각 중이다.