한 장 요약
무엇이 달라졌는가
가장 먼저 만든 것
고치기 전에, 고쳤는지 아는 방법부터
6시간 자율 작업에서 가장 위험한 상태는 무엇이 깨졌는지 모르는 것입니다. 그래서 첫 커밋은 게임 코드가 아니라 검증기였습니다.
P0 · 출혈 정지
플레이어의 진행을 파괴하던 것들
최상위 보상을 얻으면 게임이 멈췄다
GameManager.gd · damage_player()
불사조 펫의 부활 판정이 사망 확정 뒤에 있었습니다. 세이브 삭제 → 소울 선지급 → GAMEOVER 전환이 모두 끝난 다음에 부활이 일어나니, 부활에 성공한 플레이어는 앱 강제종료 외에 탈출구가 없었습니다.
수정 — 부활 판정을 요정 포션과 같은 위치(사망 확정 이전)로 올렸습니다. 세이브 삭제·소울 이중 지급·상태 고착 세 증상이 한 번에 사라졌습니다. _on_player_died()는 연출 전용으로 축소했습니다.
펫 레벨이 재시작마다 초기화됐다
SaveManager.gd · save_meta_data()
19개 필드를 직렬화하면서 pet_data 하나를 빠뜨렸습니다. 킬마다 발생하던 디스크 쓰기가 전부 헛수고였습니다.
플레이어에게 진행도 초기화 버튼이 노출됐다
dev_mode_enabled = true가 커밋된 상태였습니다. 클래스 기본값은 false인데 .tres가 덮어쓰고 있었습니다.
보스 밸런싱이 통째로 죽어 있었다
MonsterData.gd · _get_game_config()
Godot 4에서 모든 Object는 get을 갖는데 has_method("get") == false를 조건으로 걸어 함수가 항상 null을 반환했습니다. 보스 튜닝 7종이 전부 무시되고 있었습니다.
반전 — 고치자 boss_hp_multiplier 0.7이 되살아나면서 20층 보스 승률이 100%가 되어버렸습니다. 고치는 것만으로는 부족했고 수치를 다시 잡아야 했습니다.
P1 · 밸런스와 진행
승리 조건이 없는 게임에 결승선을 그었다
코드 전체에 final_stage도 game_clear도 없었습니다. 스테이지는 무한히 증가하고 모든 플레이는 패배로 끝났습니다.
중간 관문
최종 보스 (목표 50~60%)
절반쯤 이기는 난이도
P2 · 코어 루프
선택이 선택이 되었다
이 게임이 클리커가 아니라 로그라이크임을 주장하는 근거는 선택뿐인데, 그 선택 셋이 모두 형해화되어 있었습니다.
보상 4~5장 중 절반이 무효
SKIP은 완전 no-op이었고, GOLD·XP 카드는 처치 시 이미 자동 지급되는 것의 중복이었습니다.
→ 3택 고정. 즉시파워 / 장기파워 / 생존 세 축에서 하나씩. 만피에 회복 카드, 포션 만재에 포션 카드 같은 무효 선택지는 생성 단계에서 차단합니다.
이벤트 9종 중 7종이 선택지 없음
제단은 최대HP를 강제 징수하고, 상인은 골드를 묻지도 않고 차감했습니다. 정작 설명문은 전부 “~할 수 있다”로 선택을 전제했습니다.
→ 9종 전부 ‘제시 → 선택 → 결과’ 3단계. EventData.choices로 데이터 주도화해 이후 이벤트 추가 비용이 급감합니다.
상자 선택이 가짜였다
카드를 펼쳐 고르게 해놓고, 선택 직후 나머지 보상 전부를 순회하며 지급했습니다. 무엇을 눌러도 결과가 같았습니다.
→ 3장 중 1장만. 유물 확률의 등급 역전(전설 0.05 < 황금 0.10)도 바로잡았습니다.
P3 · 화면과 조작
30분 런이 오조작 한 번에 날아가지 않는다
| 문제 | 이전 | 수정 |
|---|---|---|
| 안드로이드 뒤로가기 = 앱 즉시 종료 Godot 4의 quit_on_go_back 기본값이 true |
핸들러 0개 | UIStack 오토로드 + 일시정지 패널. 모달 스택을 한 곳에서 처리 |
| 일시정지 수단 없음 | 0개 | 전투 화면 일시정지 버튼 + 하드웨어 back 과 동일 경로 |
| 오탭이 되돌릴 수 없는 결과로 22×20 InfoButton 이 110×140 카드 선택 영역에 겹침 |
15/24 가 44px 미만 | 버튼 제거 후 카드 롱프레스로 전환. 나머지 8종은 48px 이상으로 |
| 20:9 단말의 미설계 세로 영역 | 약 140px | Camera2D 좌상단 기준 + 앵커 기반 재배치 |
| 튜토리얼을 건너뛸 수 없음 | 킬 목표 30 | 스킵 버튼 + 킬 목표 14 |
P4 · 연출
누른 탭이 사라지지 않는다
거부된 탭에 반응을 줬다
초당 2회를 넘는 탭이 아무 반응 없이 사라지고 있었습니다 — 클리커에서 가장 나쁜 감각입니다. 다만 거부는 성공보다 약해야 하고 연타 중 계속 발생하므로, 화면 흔들림은 쓰지 않고 자체 throttle 을 걸었습니다. HUD 슬롯 게이지가 이유를 함께 보여줍니다.
파티클을 풀링했다
기존 _spawn_explosion()은 사망마다 ColorRect 6~12개와 Tween 6~12개를 상한 없이 만들고 0.4초 뒤 버렸습니다. 동시 사망 3마리면 순간 36노드입니다. 이제 CPUParticles2D 12개 고정 풀로 런타임 노드 증감이 0입니다.
P5 · 아트
픽셀아트 게임인데 텍스트만 벡터 폰트였다
가장 큰 발견은 픽셀 폰트가 거의 쓰이지 않고 있었다는 것입니다. Galmuri9 참조처가 데미지 숫자 한 곳뿐이었고, 나머지 게임 전체는 엔진 내장 폰트로 렌더됐습니다.
Galmuri9의 선명한 크기는 9의 배수가 아니라 10의 배수다
진단 보고서는 “9의 배수(9·18·36)”라고 적었지만 틀렸습니다. 폰트를 실제로 래스터라이즈해 측정한 결과, 부분 커버리지(회색) 픽셀 비율이 10·20·30·40px에서 정확히 0.00%, 9px에서 87.99%였습니다. unitsPerEm=1000이고 글리프가 100 유닛 그리드에 놓여 있기 때문입니다.
조치 — 전역 폰트 적용 + 안티에일리어싱 해제 + 메인 메뉴 폰트 크기를 10의 배수로. 메인 메뉴의 흐린 픽셀 비율이 45.89% → 0.00%가 됐습니다.
배경은 3색 타일을 12.8배 늘린 것, 로고는 아이템 아이콘 팩의 파일 하나였다
정작 assets/sprites/backgrounds/에 360×640 네이티브 배경 5장이 쓰이지 않은 채 있었습니다. 네이티브 배경으로 교체하고, 앱 아이콘과 타이틀 엠블럼을 기존 보스 스프라이트에서 4배 정수 NEAREST로 새로 만들었습니다.
몬스터 24/24종이 소수 배율로 렌더됐다
sprite_scale 0.8~0.9는 1px 아웃라인을 끊고 idle 부유 중 지글거리게 만듭니다. 전부 1.0으로 되돌리고 위치도 정수 픽셀로 스냅했습니다.
방법론
21개 에이전트를 파일로 갈라 붙였다
여러 에이전트가 같은 파일을 동시에 고치면 서로의 작업을 덮어씁니다. 그래서 파일 소유권을 겹치지 않게 배정하고, 경계를 넘는 연결은 계약으로 넘겨받아 직접 처리했습니다.
잘 작동한 것
- 파일 분리 배정 — 4명이 동시에 작업해도 충돌 0건
- godot 실행 금지 — 동시 실행이 임포트 캐시를 깨뜨리는 것을 막았다
- api_contract 보고 — 경계를 넘는 호출을 명시적으로 넘겨받아 통합했다
- 검증 게이트 — 세 검사를 통과해야만 커밋
사고 — 기록해 둘 것
작업 중 세션 한도에 걸려 검토자와 다음 단계 전원이 실패했습니다. 그 결과 검증되지 않은 변경 45개 파일이 작업 트리에 그대로 남았습니다 — 가장 위험한 상태입니다.
직접 검증해 복구했고 다행히 통과했지만, 교훈은 분명합니다: 병렬 워크플로우는 검증 단계까지 끝나야 안전합니다. 구현만 끝난 상태로 두면 안 됩니다.
P7 · P8
시간이 남아 두 라운드를 더 돌렸다
인스펙터가 실제로 게임을 바꾼다
GameConfig 배선율 36% → 62%. 무결성 검사의 경고가 사라졌습니다. 소비처가 아예 없는 유령 필드는 지웠습니다 — “설정처럼 보이는 죽은 값”은 없는 게 낫습니다.
폰트 크기 65곳을 10의 배수로 스냅하되, 실제 문자열 131개를 실측해 컨테이너에 들어가는 것만 키웠습니다. 넘치는 것은 키우지 않고 내렸습니다.
세이브가 더는 파괴되지 않는다
진단에서 critical 이었는데 미착수였던 항목입니다. 파싱 실패 시 세이브를 즉시 영구 삭제하고 있었습니다 — 앱이 강제 종료돼 파일이 잘렸을 뿐인데 진행도가 사라졌습니다.
원자적 쓰기(.tmp → 검증 → .bak → rename), 손상 시 격리 후 백업 복구, 마이그레이션 체인, 타입 검증을 넣었습니다.
이번 버전이 스스로 만든 문제를 잡았다
최종 스테이지를 20층으로 정하는 순간, 해금 조건이 도적 50층 · 마법사 100층 · 요정 30층인 것들이 영구 도달 불가가 되었습니다. 고치는 과정에서 새 결함을 만든 것입니다.
수정 — 클리어 횟수라는 새 축(total_clears)을 만들어 도적=첫 클리어 / 마법사=3회 / 불사조=5회로 재설계했습니다. 20층 상한에서 스테이지 축은 해상도가 없지만 클리어 횟수는 상한이 없고 이번 버전의 목표와 직결됩니다. 기존 유저의 해금 상태는 마이그레이션으로 승계합니다.
정직한 현재 위치
아직 하지 않은 것
이번 작업으로 게임은 완주 가능해졌지만 재미있어졌는지는 아직 모릅니다. 그 질문에는 사람이 플레이해야만 답할 수 있습니다.
확인되지 않은 것
- 실기기 플레이가 없다. 모든 수치는 시뮬레이터와 헤드리스 스모크 테스트 기반입니다. 손가락으로 눌러본 사람이 아직 없습니다.
- 전역 폰트 교체의 레이아웃 영향을 전 화면에서 눈으로 확인하지 못했습니다. 텍스트 폭이 달라지면 컨테이너가 넘칠 수 있습니다.
- 웹 캔버스 정렬. 헤드리스 브라우저 캡처에서 캔버스가 오른쪽으로 밀려 상단 버튼이 잘리는 것처럼 보였습니다. 셸의 CSS 에는 오프셋이 없어 소프트웨어 렌더링 중 캡처된 아티팩트로 보이지만 확증하지 못했습니다. 실제 브라우저에서 한 번 확인이 필요합니다.
- 보상 카드 구조가 바뀌어 스테이지당 수입이 달라졌는데, 시뮬레이터는 보상 카드를 모델링하지 않습니다.
다음에 할 것
- BGM. 배관은 깔았지만 곡이 0개입니다. 파일만 넣으면 즉시 동작합니다.
- 몬스터 애니메이션이 여전히 1프레임입니다. 개체별 idle 움직임은 넣었지만 스프라이트 프레임은 생성 도구 없이는 못 만듭니다.
- 실기기 성능 확인. 파티클과 전역 폰트가 저사양 안드로이드에서 어떤지 모릅니다.
- 외부 플레이테스트. 모르는 사람에게 폰을 건네고 10분을 관찰하는 것 — 이것이 다음 보고서의 데이터 소스가 되어야 합니다.