오늘 해결하려던 두 가지 문제
3일차까지는 만들 기능과 필요한 에셋이 계속 늘어났다. 이 상태로 바로 구현하면 AI가 요청할 때마다 범위를 넓히고, 사람은 빠진 이미지와 소리를 찾느라 흐름이 끊긴다. 4일차에는 두 가지를 해결하려 했다.
- 첫 프로토타입에서 만들 기능과 만들지 않을 기능을 확정한다.
- 필요한 이미지와 오디오를 반복해서 찾는 과정을 자동화한다.
이 글은 하나의 튜토리얼이 아니라 그날의 작업 기록이다. 게임 기획이 궁금하면 1번, 에셋 수집 자동화가 궁금하면 2~3번을 읽으면 된다. 뒤의 포트폴리오 작업은 같은 날 병행한 별도 작업이라 게임 구현의 필수 단계는 아니다.
1. 뱀서라이크 GDD 완성
프로젝트 방향 전환
기존 “AI Survivor”에서 뱀서라이크(Vampire Survivors 스타일) 장르로 전환했다. 이유는 명확하다. 뱀서라이크는 구조가 단순하고 반복 패턴이 많아서 AI 코드 생성에 최적화된 장르이기 때문이다. 무기 하나를 구현하면 나머지 19개는 수치와 이펙트만 바꾸면 된다. AI가 가장 잘하는 패턴 복제 작업이다.
첫 프로토타입의 완료 조건
4개 문서, 36개 피처, 5개 마일스톤으로 정리했다.
기술 스택:
| 구성 | 선택 |
|---|---|
| 렌더링 | URP (Universal Render Pipeline) |
| UI | UI Toolkit |
| 카메라 | Cinemachine |
| 입력 | New Input System |
| 반응형 | R3 Reactive Extensions |
수치 설계:
- 무기 20종 + 진화 시스템
- 패시브 아이템
- 데미지 공식, EXP 테이블, 웨이브 스포닝 규칙까지 수치화
- 레벨 커브, 적 체력 스케일링, 보스 등장 타이밍
GDD(Game Design Document)는 게임 규칙과 콘텐츠 범위를 적은 기획 문서다. 여기서 “잠금”은 영원히 수정하지 않는다는 뜻이 아니라, 첫 프로토타입을 만들 동안 새 기능을 추가하지 않는다는 작업 규칙이다. AI에게 많은 기능을 한꺼번에 맡기기보다 각 기능의 입력·결과·완료 조건을 같은 문서에서 보게 하려는 선택이었다.
현재 프로토타입 상태
GDD 작성과 병행하면서 프로토타입도 진행 중이다. 아직 초기 단계지만 기본 구조는 잡혀 있다.
필드 환경. 픽셀아트 나무, 꽃, 하트 드롭, 경험치 젬이 배치
HUD 프로토타입. HP 바, 10분 타이머, 레벨 표시, 킬 카운트, 하단 무기 슬롯 6 추가
적 스포닝 테스트. 개구리, 버섯, 슬라임 등 다양한 타입이 필드에 등장한다.
R3 Reactive 프레임워크 조사
뱀서라이크에서 무기 쿨다운, 버프 타이머, 스탯 연쇄 계산 같은 반응형 로직을 처리하기 위해 R3를 검토했다. 패키지 컴파일 에러가 발생해서 원인을 진단한 결과, R3 코어 라이브러리가 제대로 설치되지 않은 것이 문제였다. OpenUPM scoped registry 또는 NuGetForUnity를 통해 설치하는 방식으로 해결 방향을 잡았다.
2. 이미지 크롤러 데몬화 — CLI에서 24/7 파이프라인으로
왜 데몬이 필요했는가
어제 만든 크롤러는 search 명령어를 수동으로 실행하는 CLI 도구였다. 105개 에셋을 하나하나 검색하려면 여전히 시간이 많이 든다. 목표를 바꿨다. 24시간 상시 크롤링 데몬으로 전환해서, 키워드를 등록해 두면 알아서 돌아가게 만드는 것이다.
아키텍처 변경
[Crawler Thread] → Queue → [Processor Thread] → [Output Thread]
↕
[Monitor Thread]
4개 스레드 파이프라인으로 재설계했다.
| 스레드 | 역할 |
|---|---|
| Crawler | OpenGameArt, itch.io, Spriters Resource 순회하며 이미지 수집 |
| Processor | Google Cloud Vision API + 텍스트 키워드 하이브리드 분류 |
| Output | 계층형 폴더 구조로 자동 정리, 파일명 생성 |
| Monitor | 상태 모니터링, 통계 출력 |
AI 하이브리드 분류
분류 정확도를 높이기 위해 두 가지 방식을 결합했다.
- 텍스트 키워드 매칭: 파일명, 설명, 태그에서 키워드를 추출해 카테고리 추론. 무기 키워드만 67개 등록했다.
- Google Cloud Vision API: 이미지 자체를 분석해서 라벨 생성.
비용 최적화 전략: 텍스트 confidence가 0.8 이상이면 Vision API 호출을 스킵한다. 대부분의 에셋은 파일명이나 태그만으로 충분히 분류 가능하기 때문에, Vision API 비용을 크게 절감할 수 있다.
출력 구조
output/
├── Character/
│ ├── Man/
│ ├── Woman/
│ ├── Monster/
│ └── Animal/
├── Tileset/
├── Item/
├── UI/
├── Effect/
└── Background/
파일명은 Hero_Sword_Idle.png 패턴(PascalCase + underscore)으로 자동 생성한다. SQLite DedupDB와 perceptual hash로 중복을 방지하고, Vision API 결과도 캐싱해서 같은 이미지를 두 번 분석하지 않는다.
테스트
25개 이상의 Python 모듈, 87개 테스트 전체 통과. CLI 도구일 때의 56개에서 31개가 추가됐다.
3. 오디오 크롤러 — BGM + SFX 파이프라인
게임에는 그림만 필요한 게 아니다
이미지 크롤러를 만들고 나니, 오디오 에셋도 같은 문제라는 게 보였다. RPG 마을 BGM, 전투 효과음, UI 클릭 사운드 — 이것들도 일일이 찾아 다운로드하는 건 비효율적이다. 이미지 크롤러와 같은 패턴을 오디오에 적용하기로 했다.
BGM 크롤러
기존에 작업 중이던 BGM 크롤러에서 키워드 순환 버그를 수정했다. 크롤러가 첫 번째 키워드(“RPG town music”)에 고정되어 다음 키워드로 넘어가지 않는 문제였다. advance() 호출을 try/finally로 감싸서 에러가 나도 키워드가 반드시 회전하도록 했다. 큐 사이즈도 100에서 500으로 늘렸다.
SFX 크롤러 — 팀 에이전트 4명으로 신규 개발
SFX(효과음) 크롤러는 처음부터 새로 만들었다. 4명의 팀 에이전트를 투입했다.
| 에이전트 | 담당 |
|---|---|
| crawler-dev | Freesound, OpenGameArt 크롤러 모듈 |
| audio-dev | 오디오 포맷 변환, 메타데이터 추출 |
| classifier-dev | 효과음 카테고리 분류 (Attack, UI, Ambient 등) |
| infra-dev | 설정, CLI, 테스트, 인프라 |
71개 테스트 전체 통과. --stats와 --dry-run 플래그까지 검증 완료. 프로덕션 투입에는 Freesound API 키와 ffmpeg가 필요하다.
4. 포트폴리오 Flappy Bird 배경 게임
포트폴리오에 실제 게임을 넣은 이유
게임 개발자 포트폴리오인데 정작 포트폴리오 사이트에는 게임이 없었다. 히어로 섹션 배경에 Flappy Bird 스타일 게임을 넣으면, 방문자가 도착하자마자 “이 사람은 게임을 만든다”는 인상을 준다. 배경 장식이면서 실제로 플레이할 수 있는 이스터에그다.
구현 상세
게임 상태 3가지:
| 상태 | 동작 |
|---|---|
idle |
새가 사인파로 부유, 파이프 느리게 흘러감, [ space / click to play ] 표시 |
playing |
중력 + 점프 물리, 파이프 생성, 충돌 판정, 점수 |
dead |
새 추락, 800ms 후 idle로 복귀 |
픽셀아트 새 스프라이트:
16x16 그리드를 JavaScript 배열로 직접 찍었다. 3프레임 애니메이션(날개 up/mid/down), 120ms 간격. velocity 기반 회전(-25도 ~ +70도). 색상은 사이트 테마에 맞춤 — 몸체 #58a6ff(accent blue), 날개 #1f6feb, 부리 #f0883e.
배경 느낌 연출:
canvas를 pointer-events: none으로 설정하고 z-index 0에 배치했다. idle 상태에서는 35~45% 불투명도로 은은하게 보이다가, 플레이 시작 시 300ms 트랜지션으로 60~80%까지 올린다. 히어로 콘텐츠(z-index: 1)를 가리지 않으면서, 있다는 걸 알 수 있는 수준이다.
이벤트 처리 핵심:
hero.addEventListener('click', function (e) {
if (e.target.closest('a, button, .btn')) return;
jump();
});
“프로젝트 보기”, “GitHub” 버튼을 클릭하면 게임이 아닌 원래 기능이 동작한다. 빈 영역을 클릭해야 점프한다. Spacebar는 히어로가 보일 때만 동작하고, preventDefault()로 스크롤을 방지한다.
성능 최적화:
requestAnimationFrame기반 루프IntersectionObserver로 히어로가 화면에서 벗어나면 루프 일시정지devicePixelRatio지원 (최대 2 캡)prefers-reduced-motion: reduce설정 시 게임 초기화 자체를 스킵- 홈페이지(
page.url == '/')에서만 스크립트 로드 — 블로그 페이지에서는 불필요한 JS 없음
파일 변경
| 파일 | 변경 |
|---|---|
assets/js/flappy-bg.js |
신규 ~310줄, 전체 게임 엔진 (IIFE) |
_sass/_flappy-bg.scss |
신규, canvas 포지셔닝 |
_includes/hero.html |
+1줄, <canvas> 삽입 |
assets/css/main.scss |
+1줄, SCSS import |
_layouts/default.html |
+3줄, 조건부 스크립트 로드 |
5. 그 외 병렬 작업
오늘 게임 관련 외에도 여러 프로젝트를 동시에 진행했다.
| 프로젝트 | 내용 |
|---|---|
| AI Trading v3 | exchange_calendars 마이그레이션, 매매 순서 최적화 (매도→재조회→매수), 저잔고 체크 추가 |
| 포트폴리오 사이트 | 전체 폰트 Pretendard 통일, 깨진 이미지 6개 수정, site-02·04 상세 페이지 구현 |
| Vapor Clinic | 통합 테마를 4개 독립 프로젝트로 분리 (Organic Tech, Midnight Luxe, Brutalist Signal, Vapor Clinic) |
총 10개 프로젝트를 하루에 병렬 진행했다. AI 에이전트가 각 프로젝트를 독립적으로 처리하기 때문에 가능한 일이다.
회고
10개 프로젝트 병렬 진행이 가능했던 이유
- 프로젝트 간 의존성이 없다. 크롤러, GDD, 포트폴리오, 트레이딩 봇 — 전부 독립적이다. 하나가 막혀도 나머지에 영향이 없다.
- 하니스 시스템이 컨텍스트를 유지한다. 각 프로젝트의 CLAUDE.md와 규칙 파일이 AI에게 매번 상황을 설명하는 비용을 없앤다.
- 모듈화된 설계가 병렬 작업을 가능하게 한다. SFX 크롤러처럼 4명이 동시에 작업할 수 있었던 건 모듈 경계가 명확했기 때문이다.
작성이 아닌 설계에 시간을 써야 한다
오늘 가장 시간을 많이 쓴 건 코드 작성이 아니라 GDD 수치 설계와 크롤러 아키텍처 결정이었다. AI가 코드를 쓰는 속도는 이미 충분히 빠르다. 병목은 “무엇을 만들 것인가”를 결정하는 과정이다. 명확한 스펙을 주면 AI는 정확하게 구현하고, 모호한 지시를 주면 AI는 모호하게 구현한다.
다음 단계
- 뱀서라이크 Phase 1 구현 착수 — Player 이동, 기본 무기 1종, 적 스포너. GDD 기반으로 AI에게 스펙 전달
- 크롤러 실전 투입 — 이미지 + 오디오 크롤러를 실제로 돌려서 에셋 수집 시작
- R3 프레임워크 설치 완료 — OpenUPM으로 설치 후 무기 쿨다운 시스템에 적용
- 수집된 에셋 Unity 연동 — 크롤러 출력 폴더 → Unity 프로젝트 자동 임포트
GDD가 잠겼고, 에셋 파이프라인이 갖춰졌다. 내일부터는 진짜 게임을 만든다.
하루 10개 프로젝트를 병렬 진행하며, 뱀서라이크 GDD 잠금 + 크롤러 데몬화 + 오디오 파이프라인 + 포트폴리오 배경 게임까지 구축한 기록이다.
댓글