이 글은 Today I Learn 시리즈의 120번째 기록입니다. (총 213개)

손그림 두 장을 넣은 날

손그림을 넣었더니 색이 사라졌다

손그림 태극과 복주머니를 도안으로 넣었다. 게임에서 보니 복주머니의 파란 리본과 금색 동전이 통째로 없어져 있었다.

도안을 만드는 과정은 원래 사진 같은 그림에 맞춰져 있었다. 부드럽게 줄이는 방식(이웃 픽셀을 섞어 크기를 줄이는 것)은 사진에서는 자연스럽지만, 칸 단위로 찍은 픽셀 그림에서는 경계마다 원래 없던 중간색을 만든다. 작은 요소는 그 중간색에 밀려 사라진다. 픽셀 그림은 최근접 방식(섞지 않고 가장 가까운 픽셀 하나를 그대로 가져오는 것)으로 줄이게 하자 파랑과 금색이 돌아왔다.

손그림 가장자리에 남는 얇은 색도 문제였다. 면적 1~2%짜리 색이 따로 잡히는데, 이 게임에서는 색 하나가 바구니 하나다. 칸 몇 개를 위해 바구니 하나를 쓰게 되니 3% 미만은 가까운 색에 흡수시켰다.

  • 사진과 그림은 같은 길로 넣으면 안 된다. 들여오는 소재의 성격이 바뀌면 손질하는 방식도 바꿔야 한다
  • 게임 규칙이 소재를 읽는 단위(여기서는 색 하나 = 바구니 하나)를 먼저 떠올리면, 무엇을 지워도 되는지가 정해진다

살려 넣었더니 어느 난이도에도 안 맞았다

색을 살려 넣고 나니 이번엔 복주머니가 어느 자리에 넣어도 “너무 쉬움”이었다. 여섯 곳에 넣어 봤는데 여섯 번 다 그랬다. 같은 3색인 태극은 여섯 중 다섯을 맞췄다.

처음엔 다시 그려서 생긴 문제인 줄 알았다. 그런데 예전 복주머니도 똑같이 쉬웠다. 차이는 색 면적이었다.

태극      45% / 41% / 14%   → 목표 난이도 6곳 중 5곳 적중
복주머니  86% /  8% /  6%   → 6곳 중 0곳

한 색이 그림 대부분을 차지하면 부을 순서를 고민할 거리가 없다. 벽을 아무리 깔아도 어려워지지 않는다. 두 색이 비슷한 덩어리면 어느 쪽을 먼저 붓느냐가 판을 가른다.

앞선 TIL 1에서 색이 두 개뿐인 도안은 어떤 배치로도 안 어려워진다고 했다. 이번에 보니 색 개수가 아니라 면적이 어떻게 나뉘는지가 정한다.

  • 그림 솜씨 문제가 아니라 구성의 문제였다. 난이도가 이상하면 그린 것보다 나뉜 비율을 먼저 본다
  • 도안을 새로 그릴 때도 “몇 색인가”보다 “색이 얼마나 고르게 나뉘는가”를 본다

그림 두 장을 바꿨는데 469개 레벨이 달라졌다

두 장을 교체하고 레벨을 다시 만들었더니 500개 중 469개의 그림이 바뀌어 있었다.

도안을 난이도 점수 순으로 줄 세워 배정하는 구조라, 한 도안의 점수가 바뀌면 그 뒤 배정이 전부 한 칸씩 밀린다. 바꾼 것과 무관한 레벨까지 딸려 간다.

앞선 TIL 16에서 레벨이 앱 안에 묶여 있으니 이미 낸 구간은 얼려 두기로(동결) 했다. 이날 정한 것은 그걸 언제 하느냐다. 출시 자체에는 동결이 필요 없다. 그날 있는 레벨을 그대로 내보내면 된다. 없으면 안 되는 시점은 출시 후 첫 갱신이다. 그래서 동결은 그때까지 미루기로 했다.

  • 아직 플레이어가 없으면 전체를 다시 만드는 게 가장 단순하다. 300단계까지 간 사람이 생기면 지나온 그림이 전부 바뀌는 일이 된다
  • 필요한 장치라도 “언제부터 없으면 안 되는가”를 따지면 지금 안 해도 되는 것이 보인다

소스를 들여올 때

작아 보인 것과 뭉개진 것은 원인이 달랐다

받아온 게임 에셋 묶음(Kenney) 도안을 보니 작고 색이 뭉개져 있었다. 원인을 찾아보니 두 가지가 겹쳐 있었다.

작은 쪽은 고칠 수 있었다. 투명 여백을 잘라내는 처리를 나중에 추가하는 바람에 먼저 받은 묶음에는 적용이 안 돼 있었다. 다시 받으니 그림이 화면을 채우는 비율이 0.19에서 0.46이 됐고, 커진 만큼 색이 살아 통과 도안도 69종에서 121종으로 늘었다.

뭉개지는 쪽은 못 고친다. 3D로 렌더한 그림이라 음영이 많고, 작은 격자에 몇 색으로 줄이면 중간톤이 뭉개진다. 그림마다 다른 문제가 아니라 그 소스의 성격이다.

  • 증상 하나에 원인이 둘일 수 있다. 고칠 수 있는 원인과 소스의 성격을 갈라 놓아야 헛손질을 안 한다
  • 처리 단계를 나중에 추가하면 먼저 들어온 것에는 안 걸려 있다. 새 단계를 넣었으면 이미 받은 것도 다시 통과시킨다

이름은 출처가 아니었다

도안 뷰어에 어느 소스에서 온 도안인지 보이게 했더니, 직접 만든 도안이 199개로 잡혔다고 Claude가 알려 줬다. 실제로 직접 만든 건 17개였다.

출처를 이름 앞머리로 가르고 있었다. 한국 손그림 도안에는 k_를 붙이기로 했었는데, Kenney 파일 중에도 k_로 시작하는 것이 있었다. 앞머리가 없는 표준 이모지 이름(apple·heart 같은)도 직접 만든 것 쪽으로 섞였다. 판정을 이름 대신 실제 소스 목록으로 바꿨다. 앞선 TIL 11에서 이름이 같은 도안이 조용히 사라진 일이 있었는데, 같은 뿌리다.

  • 이름 앞머리는 붙일 때 편하려고 정한 라벨이지 출처가 아니다. 소스가 늘면 다른 소스와 겹친다
  • 출처를 알고 싶으면 출처를 직접 본다

색을 손볼 때

코인이 어두워 보인 건 배경 탓이었다

하트·코인 아이콘을 그림으로 바꾸고 게임 화면에서 보니 금화가 어두웠다. 재 보니 밝기가 151로 원래 있던 노란 원(209)보다 낮았다. 다만 어두운 배경에서는 괜찮고 밝은 배경에서만 탁해 보였다.

밝히는 방법을 세 번 바꿔 가며 결과를 봤는데, 방법마다 잃는 게 달랐다.

색에 배수 곱하기        밝기는 맞음 / 코인의 60%가 순백으로 날아가 각인이 사라짐
세 채널에 감마(곡선)    무늬는 살음 / 금색이 베이지로 바램
밝기에만 감마           무늬도 색도 유지 / 151 → 178

마지막 방식으로 밝혀 그림 자체에 구워 두고, 어두운 배경에서는 그릴 때 낮추게 했다. 낮추는 쪽은 날아갈 밝은 부분이 없어 안전하다.

  • 같은 에셋이 배경에 따라 다르게 보인다. “어둡다”는 말을 들으면 어디 위에서 어두운지부터 본다
  • “밝게”에도 방법이 여럿이고 각자 무언가를 잃는다. 무늬를 잃는지 색을 잃는지 결과를 나란히 놓고 고른다

채도를 올릴 수 있는 한계는 그림마다 다르다

뷰어에 “칙칙한 것만” 모아 보는 필터가 생기면서 그 도안들을 진하게 하는 작업이 이어졌다. 일괄로 진하게 하면 이미 진한 색은 과해지고 가까웠던 색끼리 붙는다. 이 게임에서 색이 붙으면 어느 바구니에 부을지 알 수 없다.

그림마다 색 구분 기준을 안 깨는 최대 배율을 따로 찾고, 절대 상한도 뒀다. 225개 중 210개가 나아졌고 15개는 그대로 뒀다. 백자·백조처럼 흰색이 본질인 도안은 진하게 하면 그 도안이 아니게 된다.

  • 일괄 보정은 평균에 맞춘 보정이다. 그림마다 견딜 수 있는 한도가 다르면 한도를 그림마다 잰다
  • 앞선 TIL 8에서 지키기로 한 흰색은 다시 훼손하지 않기로 했다. 보정에서도 같은 것을 지킨다

일일 보상 카드

아홉 장이 같은 박자로 뛰니 기계 같았다

일일 보상을 상자에서 카드로 바꾸면서, 고르기 전 카드들이 숨쉬듯 움직이게 했다. 그랬더니 아홉 장이 전부 같은 박자로 커졌다 작아졌다. 카드마다 박자를 조금씩 밀게 했더니 물결처럼 번갈아 움직였다.

앞선 TIL 8에서 대여섯 개가 동시에 뒤집히는 게 어수선해서 속도를 흩었는데, 여기서도 같은 결이었다.

  • 여럿이 똑같이 움직이면 살아 있는 게 아니라 기계로 보인다. 시작점이나 박자를 흩는다

출시 준비

업로드 키는 앱 서명 키가 아니다

출시 파일에 서명을 붙이면서 키를 어떻게 다룰지 정했다. 새로 올리는 앱은 Google Play가 앱 서명 키를 대신 보관한다. 내가 만들어 쥐는 키는 업로드 키로, 올린 파일이 내 것인지 확인하는 용도다.

  • 업로드 키를 잃으면 재설정을 요청할 수 있다. 며칠 걸리지만 복구된다. “키를 잃으면 앱을 영영 못 고친다”는 예전 이야기다
  • 그래도 재설정하는 동안은 업데이트가 막힌다. 그래서 백업은 내가 직접 한다

키 파일은 저장소 밖에 둔다

키 파일과 비밀번호는 내가 직접 보관하고, Claude에게도 알려 주지 않기로 했다. 코드를 짜는 쪽은 키가 어디 있는지만 알면 되고 키 자체를 알 필요는 없다.

저장소 안에 두고 제외 목록에 넣는 방식은 한 가지를 못 막는다. 추적 안 되는 파일을 정리하는 명령 한 번, 또는 저장소를 새로 받는 순간 사라진다.

  • 키 파일은 저장소 밖 별도 폴더에 두고, 설정이 그 경로를 가리키게 한다
  • 백업은 서로 다른 매체 두 곳 이상에 둔다
  • 키를 쓰는 사람과 코드를 짜는 쪽을 나눈다. 비밀은 아는 곳이 적을수록 새는 곳도 적다
  • 별칭·지문 같은 정보만 적어 두면 같은 키를 다시 만들 수 없다. 파일 자체가 백업돼야 한다
  • 비밀번호는 저장소에 적지 않는다. 비공개 저장소라도 이력이 남고, 공개로 바꾸거나 사람을 들이는 순간 드러난다

영어로 바꿔 보니

레이아웃은 만들 때 쓴 언어에 맞춰져 있다

한국어·영어 전환을 넣었더니 Claude가 영어에서 설정 화면의 토글 줄이 넘친다고 알려 줬다. 직접 영어로 바꿔 확인해 보니 정말 넘쳐 있었다. 한국어로 “출시 전 제거”였던 자리가 영어로는 “Remove before release”였다.

글자가 남는 폭 안에서 줄어들고 그래도 길면 말줄임(…)이 되게 바꾸고, 영어로 설정 화면을 끝까지 그려 넘치면 실패하는 테스트를 넣었다. 다른 화면은 아직 그런 검사가 없어서 영어로 직접 훑어봐야 한다.

  • 한 언어로 만든 화면은 그 언어 길이에 맞춰져 있다. 언어를 더하면 모든 화면을 그 언어로 한 번은 봐야 한다

보상 표시

받을 수 없는 양을 적어 두면 속인 게 된다

광고를 보면 하트 5개를 주는 기능을 넣었다. 그런데 최대치가 5라서 4개 있을 때 보면 1개만 들어오고 4개는 버려진다. 하루 한 번뿐인 기회를 5분의 1 값에 쓰는 셈인데, 화면에는 +5라고 적혀 있었다.

카드에 정량이 아니라 지금 실제로 들어올 개수를 적어 달라고 했다. 막지는 않았다. 지금 당장 한 판 하려고 1개를 받는 건 손해가 아니라 선택이다.

  • 한도가 있는 보상은 “주는 양”이 아니라 “받는 양”을 보여 준다
  • 숫자가 사실대로 적혀 있으면 플레이어의 선택이다. 막을지 말지보다 제대로 알릴지가 먼저다

Series: Today I Learn

1 C++ 자료형(Data Type) 2 MD5 vs pHash 3 C++에서 함수의 선언과 정의 4 Tkinter padx, pady 5 메모리와 포인터 변수 6 Call by Value, Call by Reference, Call by Pointer 비교 7 const 8 Gemfile — Jekyll 프로젝트의 의존성 파일 9 kramdown-parser-gfm — Jekyll의 GFM 파서 10 파서(Parser) 11 AHU vs OHU 12 I might try it vs I'll try it 뉘앙스 차이 13 SESSION_EXPIRE_AT_BROWSER_CLOSE=True 14 configuration key 15 Git stash vs discard 16 subprocess.Popen으로 Windows 탐색기에 명령어를 전달 17 Post 잔디 분석하기 18 Google Sheets Sync 최적화 19 DSL (Domain Specific Language)과 GPL (General Purpose Language) 20 마크다운 표 그리는 방법 21 쿼리 파라미터(Query Parameter). 기존 QR코드 재활용 22 Django 보안 취약점 점검 및 수정 23 OOP Object-Oriented Programming 객체 지향 프로그래밍 24 Fernet 대칭 암호화 25 Jekyll 코드블록 안의 Liquid 태그 26 습관만들기 Pawbit TIL 1 27 insertOnConflictUpdate vs DoUpdate(target) 28 세션 필터 29 아코디언(Accordiaon) UI를 펼친상태로 만들기 30 input의 step 31 습관만들기 Pawbit TIL 2 32 습관만들기 Pawbit TIL 3 33 Word Cloud 34 Google Sheets를 데이터 버스로(with AppSheet) 35 Django 모델 텍스트 필드 자동 수집 패턴 36 localStorage로 섹션 토글 상태 유지 37 순차 ID 생성(`select_for_update()` + `max()` 조합) 38 역참조 검색과 distinct() 39 xlsx 다운로드와 로딩 오버레이 충돌 40 Android 파일 공유 MIME 타입 41 AssetManifest — Flutter 빌드 타임 asset 목록 런타임 조회 42 크레센도 Phaser + TypeScript TIL 1 43 크레센도 Phaser + TypeScript TIL 2 44 크레센도 Phaser + TypeScript TIL 3 45 크레센도 Phaser + TypeScript TIL 4 46 크레센도 Phaser + TypeScript TIL 5 47 여둘까 Office Layout TIL 1 48 습관만들기 Pawbit TIL 4 49 여둘까 Office Layout TIL 2 50 여둘까 Office Layout TIL 3 51 크레센도 Phaser + TypeScript TIL 6 52 UTF-8 BOM과 PowerShell 파일 쓰기 53 소리꽃 KeyBloom TIL 1 54 습관만들기 Pawbit TIL 5 55 여둘까 Office Layout TIL 4 56 소리꽃 KeyBloom TIL 2 57 소리꽃 KeyBloom TIL 3 58 메트로놈 Simple Metronome TIL 1 59 소리꽃 KeyBloom TIL 4 60 메트로놈 Simple Metronome TIL 2 61 소리꽃 KeyBloom TIL 5 62 습관만들기 Pawbit TIL 6 63 크레센도 Phaser + TypeScript TIL 7 64 메트로놈 Simple Metronome TIL 3 65 소설 타임라인 관리 도구 Lumior TIL 1 66 습관만들기 Pawbit TIL 7 67 정적 블로그 SEO 정비와 Pagefind 검색 도입 68 크레센도 Phaser + TypeScript TIL 8 69 메트로놈 Simple Metronome TIL 4 70 습관만들기 Pawbit TIL 8 71 안드로이드 AudioTrack 연속 재생, 실측 피커 정렬, 카메라 토치 플래시 72 메트로놈 Simple Metronome TIL 5 73 모래게임 Sandrop TIL 1 74 습관만들기 Pawbit TIL 9 75 메트로놈 Simple Metronome TIL 6 76 모래게임 Sandrop TIL 2 77 모래게임 Sandrop TIL 3 78 습관만들기 Pawbit TIL 10 79 습관만들기 Pawbit TIL 11 80 메트로놈 Simple Metronome TIL 7 81 모래게임 Sandrop TIL 5 82 모래게임 Sandrop TIL 4 83 습관만들기 Pawbit TIL 12 84 모래게임 Sandrop TIL 6 85 소리꽃 KeyBloom TIL 6 86 모래게임 Sandrop TIL 7 87 모래게임 Sandrop TIL 8 88 소리꽃 KeyBloom TIL 7 89 모래게임 Sandrop TIL 9 90 소리꽃 KeyBloom TIL 8 91 모래게임 Sandrop TIL 10 92 소리꽃 KeyBloom TIL 9 93 콘티온 ContiOn TIL 1 94 소리꽃 KeyBloom TIL 10 95 콘티온 ContiOn TIL 2 96 습관만들기 Pawbit TIL 13 97 콘티온 ContiOn TIL 3 98 모래게임 Sandrop TIL 11 99 소리꽃 KeyBloom TIL 11 100 여둘까 Office Layout TIL 5 101 모래게임 Sandrop TIL 12 102 모래게임 Sandrop TIL 13 103 콘티온 ContiOn TIL 4 104 모래게임 Sandrop TIL 14 105 소리꽃 KeyBloom TIL 12 106 습관만들기 Pawbit TIL 14 107 모래게임 Sandrop TIL 15 108 모래게임 Sandrop TIL 16 109 소리꽃 KeyBloom TIL 13 110 온실 GreenHouse TIL 1 111 콘티온 ContiOn TIL 5 112 모래게임 Sandrop TIL 17 113 소리꽃 KeyBloom TIL 14 114 온실 GreenHouse TIL 2 115 콘티온 ContiOn TIL 6 116 모래게임 Sandrop TIL 18 117 콘티온 ContiOn TIL 7 118 모래게임 Sandrop TIL 19 119 소리꽃 KeyBloom TIL 15 120 모래게임 Sandrop TIL 20 읽는 중 121 모래게임 Sandrop TIL 21 122 소리꽃 KeyBloom TIL 16 123 소리꽃 KeyBloom TIL 17 124 소리꽃 KeyBloom TIL 18 125 여둘까 Office Layout TIL 6 126 소리꽃 KeyBloom TIL 19 127 소리꽃 KeyBloom TIL 20 128 콘티온 ContiOn TIL 8 129 콘티온 ContiOn TIL 9 130 로그스톤 상표 셀프 출원 TIL 1 131 소리꽃 KeyBloom TIL 21 132 로그스톤 샵 LogStone Shop TIL 1 133 소리꽃 KeyBloom TIL 22 134 로그스톤 샵 LogStone Shop TIL 2 135 소리꽃 KeyBloom TIL 23 136 모래게임 Sandrop TIL 22 137 모래게임 Sandrop TIL 23 138 소리꽃 KeyBloom TIL 24 139 로그스톤 샵 LogStone Shop TIL 3 140 모래게임 Sandrop TIL 24 141 소리꽃 KeyBloom TIL 25 142 모래게임 Sandrop TIL 25 143 MiniMacro TIL 1 144 모래게임 Sandrop TIL 26 145 콘티온 ContiOn TIL 10 146 Astro가 무엇인지, 왜 옮기는지 147 모래게임 Sandrop TIL 27 148 소리꽃 KeyBloom TIL 26 149 MiniMacro TIL 2 150 로그스톤 샵 LogStone Shop TIL 4 151 메트로놈 Simple Metronome TIL 8 152 모래게임 Sandrop TIL 28 153 여둘까 Office Layout TIL 7 154 메트로놈 Simple Metronome TIL 9 155 블로그 Astro 이관 TIL 156 여둘까 Office Layout TIL 8 157 로그스톤 샵 LogStone Shop TIL 5 158 모래게임 Sandrop TIL 29 159 오픈데이 Openday TIL 1 160 로그스톤 샵 LogStone Shop TIL 6 161 모래게임 Sandrop TIL 30 162 오픈데이 Openday TIL 2 163 모래게임 Sandrop TIL 31 164 Unreal Engine MCP TIL 1 165 모래게임 Sandrop TIL 32 166 소리꽃 KeyBloom TIL 27 167 콘티온 ContiOn TIL 11 168 오픈데이 Openday TIL 3 169 로그스톤 샵 LogStone Shop TIL 7 170 모래게임 Sandrop TIL 33 171 소리꽃 KeyBloom TIL 28 172 오픈데이 Openday TIL 4 173 여둘까 Office Layout TIL 9 174 오픈데이 Openday TIL 5 175 ScorePlayer TIL 1 176 모래게임 Sandrop TIL 34 177 BuildingHub TIL 1 178 ScorePlayer TIL 2 179 여둘까 Office Layout TIL 10 180 BuildingHub TIL 2 181 ScorePlayer TIL 3 182 Unreal Engine MCP TIL 2 183 궁 미로 PalaceMaze TIL 1 184 메트로놈 Simple Metronome TIL 10 185 메트로놈 Simple Metronome TIL 11 186 오픈데이 Openday TIL 6 187 BuildingHub TIL 3 188 Obsidian vault에서 코드만 빼기 — directory junction 189 ScorePlayer TIL 4 190 여둘까 Office Layout TIL 11 191 오픈데이 Openday TIL 7 192 URL은 바뀔 수 있는 것에 묶지 않는다 193 도구는 기능이 아니라 내 일에 맞는지로 고른다 194 돌이키기 힘든 변경은 작게 먼저 확인한다 195 궁 미로 PalaceMaze TIL 2 196 궁 미로 PalaceMaze TIL 3 197 소리꽃 KeyBloom TIL 29 198 오픈데이 Openday TIL 8 199 BuildingHub TIL 4 200 ScorePlayer TIL 5 201 로그스톤 샵 LogStone Shop TIL 8 202 여둘까 Office Layout TIL 12 203 오픈데이 Openday TIL 9 204 BuildingHub TIL 5 205 MiniMacro TIL 3 206 소리꽃 KeyBloom TIL 30 207 오픈데이 Openday TIL 10 208 여둘까 Office Layout TIL 13 209 소리꽃 KeyBloom TIL 31 210 궁 미로 PalaceMaze TIL 4 211 로그스톤 샵 LogStone Shop TIL 9 212 로그스톤 샵 LogStone Shop TIL 10 213 소리꽃 KeyBloom TIL 32