습관만들기 Pawbit TIL 2
이 글은 Today I Learn 시리즈의 31번째 기록입니다. (총 213개)
퍼즐을 켜 보니 같은 그림이 아홉 장 깔려 있었다
퍼즐 화면 첫 버전을 돌려 봤는데, 그림이 아홉 조각으로 나뉜 게 아니라 같은 그림이 작게 줄어든 채 아홉 칸에 하나씩 들어가 있었다.

칸을 격자로 늘어놓는 GridView에 그림을 그대로 넣으면 이렇게 된다. Flutter에서는 부모가 자식에게 크기 제약(constraint)을 내려주고 자식은 그걸 그대로 받는 게 기본이라, 그림 전체가 칸 크기 안으로 억지로 들어간다.
자르지 않고 창을 옮겨서 풀었다
바꾼 방식은 그림을 아홉 장으로 자르는 게 아니었다. 원본 한 장을 칸의 세 배 크기로 키워 두고, 칸마다 그 큰 그림의 다른 부분만 보이게 한다. 칸은 창문이고, 창에 걸리는 부분만 보인다.


필요한 부품은 셋이다.
- OverflowBox — 부모의 제약을 무시하고 자식에게 원하는 크기를 준다. 그림을 칸보다 크게 키우는 역할이다
- ClipRect — 칸 밖으로 삐져나온 부분을 잘라 낸다. 창틀 역할이다
- Alignment(x, y) — 큰 그림의 어느 지점을 칸에 맞출지 비율로 정한다. 왼쪽·위 끝이 -1, 가운데가 0, 오른쪽·아래 끝이 +1이다
| 칸 위치 | Alignment | 결과 |
|---|---|---|
| 좌상단 | (-1, -1) | 그림의 좌상단이 칸에 맞는다 |
| 가운데 | (0, 0) | 그림의 가운데가 칸에 맞는다 |
| 우하단 | (+1, +1) | 그림의 우하단이 칸에 맞는다 |

위치를 픽셀이 아니라 비율로 잡으니, 칸 크기가 바뀌든 격자가 3×3에서 7×7로 늘든 식이 그대로다.
원판을 1:1로 정해 둔 게 여기서 맞물렸다
전날 퍼즐 밸런스를 짜면서 난이도를 3×3·5×5·7×7 정방형 격자로 바꾸고, 그림 원판 규격을 1:1로 통일하기로 했다. 어떤 난이도를 골라도 조각이 정사각형으로 나오게 하고, 원판을 난이도마다 따로 만들지 않아 제작 비용을 관리하려는 결정이었다.
창을 옮기는 방식이 이 결정과 맞물린다. 조각 파일을 따로 만들지 않으니 1:1 그림 한 장이 세 난이도를 전부 그대로 커버한다.
- 판단: 관리해야 할 수가 조각 파일 수가 아니라 그림 수로 유지된다. 콘텐츠를 계속 공급해야 하는 게임에서는 이 차이가 제작 부담을 가른다.
웹의 배경 그림과 같은 원리였다
알고 보니 웹 CSS에서 배경 그림을 다루는 방식과 똑같다.
.cell {
background-size: 300% 300%; /* OverflowBox — 크게 키우기 */
background-position: 0% 0%; /* Alignment — 볼 위치 */
overflow: hidden; /* ClipRect — 나머지 잘라 내기 */
}
- 판단: 새 프레임워크의 부품 이름을 하나씩 외우기보다, 이미 아는 어느 개념과 같은지 찾는 게 빠르다.
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