pygame-gb 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Chawanwit Akarajirathanachot
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,248 @@
1
+ Metadata-Version: 2.4
2
+ Name: pygame-gb
3
+ Version: 0.1.0
4
+ Summary: A Game Boy-style 2D game making library for Python
5
+ Author-email: Chawanwit Akarajirathanachot <chawanwit.akarajirathanachot@gmail.com>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2026 Chawanwit Akarajirathanachot
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Project-URL: Homepage, https://github.com/Karibura-Cyber/PyGB
29
+ Project-URL: Documentation, https://github.com/Karibura-Cyber/PyGB#readme
30
+ Project-URL: Bug Tracker, https://github.com/Karibura-Cyber/PyGB/issues
31
+ Project-URL: Source, https://github.com/Karibura-Cyber/PyGB
32
+ Keywords: gameboy,game-boy,retro,pixel,pygame,2d,game-engine,tilemap,tiled,sprite
33
+ Classifier: Development Status :: 3 - Alpha
34
+ Classifier: Intended Audience :: Developers
35
+ Classifier: Intended Audience :: Education
36
+ Classifier: License :: OSI Approved :: MIT License
37
+ Classifier: Operating System :: OS Independent
38
+ Classifier: Programming Language :: Python :: 3
39
+ Classifier: Programming Language :: Python :: 3.9
40
+ Classifier: Programming Language :: Python :: 3.10
41
+ Classifier: Programming Language :: Python :: 3.11
42
+ Classifier: Programming Language :: Python :: 3.12
43
+ Classifier: Programming Language :: Python :: 3.13
44
+ Classifier: Programming Language :: Python :: 3.14
45
+ Classifier: Topic :: Games/Entertainment
46
+ Classifier: Topic :: Multimedia :: Graphics
47
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
48
+ Requires-Python: >=3.9
49
+ Description-Content-Type: text/markdown
50
+ License-File: LICENSE
51
+ Requires-Dist: pygame-ce>=2.5
52
+ Provides-Extra: tmx
53
+ Requires-Dist: pytmx>=3.31; extra == "tmx"
54
+ Provides-Extra: image
55
+ Requires-Dist: Pillow>=9.0; extra == "image"
56
+ Provides-Extra: all
57
+ Requires-Dist: pytmx>=3.31; extra == "all"
58
+ Requires-Dist: Pillow>=9.0; extra == "all"
59
+ Dynamic: license-file
60
+
61
+ # PyGB
62
+
63
+ A **Game Boy-style 2D game making library** for Python, built on [pygame-ce](https://pyga.me).
64
+
65
+ 160×144 viewport · 4-colour palette · GB-authentic audio channels · Tiled TMX map support · Collision editor
66
+
67
+ ---
68
+
69
+ ## Install
70
+
71
+ ```bash
72
+ pip install pygb
73
+ ```
74
+
75
+ **Optional extras:**
76
+
77
+ ```bash
78
+ pip install "pygb[tmx]" # Tiled .tmx map support (pytmx)
79
+ pip install "pygb[image]" # PNG tileset loading (Pillow)
80
+ pip install "pygb[all]" # Both of the above
81
+ ```
82
+
83
+ ---
84
+
85
+ ## Quick Start
86
+
87
+ ```python
88
+ from pygb import GameBoy, Tile
89
+ import pygb.color as color
90
+
91
+ gb = GameBoy(title="My Game", scale=3, palette=color.DMG)
92
+
93
+ player_tile = Tile([
94
+ [0, 0, 1, 1, 1, 1, 0, 0],
95
+ [0, 1, 3, 3, 3, 3, 1, 0],
96
+ [0, 1, 3, 2, 2, 3, 1, 0],
97
+ [0, 1, 3, 3, 3, 3, 1, 0],
98
+ [0, 0, 1, 1, 1, 1, 0, 0],
99
+ [0, 0, 1, 0, 0, 1, 0, 0],
100
+ [0, 0, 1, 0, 0, 1, 0, 0],
101
+ [0, 0, 0, 0, 0, 0, 0, 0],
102
+ ])
103
+ player = gb.create_sprite(player_tile, x=76, y=68)
104
+
105
+ @gb.on_update
106
+ def update():
107
+ dx, dy = gb.input.direction()
108
+ player.move(dx * 2, dy * 2)
109
+ player.clamp(0, 0, 152, 136)
110
+ if dx < 0: player.flip_x = True
111
+ elif dx > 0: player.flip_x = False
112
+
113
+ gb.run()
114
+ ```
115
+
116
+ ---
117
+
118
+ ## TMX Map Example
119
+
120
+ Load a full-colour Tiled map with camera and tile collision:
121
+
122
+ ```python
123
+ import os, json
124
+ from pygb import GameBoy, Tile, Camera, CollisionMap, load_tmx, clamp
125
+
126
+ gb = GameBoy(title="TMX Demo", scale=3)
127
+
128
+ @gb.on_start
129
+ def init():
130
+ global result, cmap, player, cam, px, py
131
+
132
+ result = load_tmx(gb, "level.tmx")
133
+ gb.graphics.bg_enabled = False # full-colour rendering via on_draw
134
+
135
+ cmap = CollisionMap(result.map_cols, result.map_rows, tile_size=result.tile_size)
136
+ if os.path.exists("level_collision.json"):
137
+ with open("level_collision.json") as f:
138
+ saved = json.load(f)
139
+ cmap.from_grid(saved["data"], solid_value=1)
140
+
141
+ px, py = float(result.world_w // 2), float(result.world_h // 2)
142
+ cam = Camera(gb.graphics,
143
+ world_w=result.world_w, world_h=result.world_h,
144
+ screen_w=gb.width, screen_h=gb.height)
145
+ cam.follow(px, py, smooth=1.0)
146
+
147
+ @gb.on_update
148
+ def update():
149
+ global px, py
150
+ dx, dy = gb.input.direction()
151
+ px, py = cmap.resolve(px, py, 8, 8, dx * 2, dy * 2)
152
+ px = clamp(px, 0, result.world_w - 8)
153
+ py = clamp(py, 0, result.world_h - 8)
154
+ cam.follow(px, py, smooth=0.15)
155
+
156
+ @gb.on_draw
157
+ def draw():
158
+ ts, sx, sy = result.tile_size, gb.graphics.scroll_x, gb.graphics.scroll_y
159
+ gb.surface.fill((0, 0, 0))
160
+ for name in result.layer_order:
161
+ tilemap = result.layers[name]
162
+ cols, rows = gb.width // ts + 2, gb.height // ts + 2
163
+ for ty in range(rows):
164
+ for tx in range(cols):
165
+ idx = tilemap.get((tx + sx // ts) % tilemap.WIDTH,
166
+ (ty + sy // ts) % tilemap.HEIGHT)
167
+ if idx in result.surfaces:
168
+ gb.surface.blit(result.surfaces[idx],
169
+ (tx * ts - sx % ts, ty * ts - sy % ts))
170
+
171
+ gb.run()
172
+ ```
173
+
174
+ ---
175
+
176
+ ## Collision Editor
177
+
178
+ Paint solid/passable tiles on a PNG tileset or a Tiled `.tmx` map and save as JSON:
179
+
180
+ ```bash
181
+ # PNG tileset
182
+ pygb-editor tileset.png
183
+ pygb-editor tileset.png output.json
184
+
185
+ # Tiled TMX map (all layers rendered automatically)
186
+ pygb-editor level.tmx
187
+ pygb-editor level.tmx level_collision.json
188
+
189
+ # Advanced editor with startup dialog
190
+ pygb-collision
191
+ pygb-collision tileset.png
192
+ pygb-collision --blank 20x18 blank_collision.json
193
+ ```
194
+
195
+ | Key | Action |
196
+ |-----|--------|
197
+ | Left click / drag | Mark tiles solid |
198
+ | Right click / drag | Mark tiles passable |
199
+ | Middle drag | Pan |
200
+ | Scroll | Zoom in / out |
201
+ | `S` | Save JSON |
202
+ | `Z` | Undo |
203
+ | `R` | Clear all |
204
+ | `Escape` | Quit |
205
+
206
+ ---
207
+
208
+ ## Features
209
+
210
+ | Feature | Details |
211
+ |---------|---------|
212
+ | Viewport | 160×144 px (configurable) |
213
+ | Tile size | Any size (default 8×8, auto-detected) |
214
+ | VRAM | 256 tiles max |
215
+ | Sprites | Position, flip, palette, AABB collision |
216
+ | Tilemaps | BG (scrollable) + Window (HUD overlay) |
217
+ | Palettes | DMG · GRAY · POCKET · GBC |
218
+ | Audio | 2× Pulse · Wave · Noise (GB-style) |
219
+ | TMX loader | Full-colour rendering via pytmx |
220
+ | Collision | Tile-resolution AABB with wall sliding |
221
+ | Font | Built-in 8×8 bitmap font |
222
+ | Utilities | Camera · Timer · Animation · RNG · Rect |
223
+
224
+ ---
225
+
226
+ ## Lifecycle Hooks
227
+
228
+ ```python
229
+ @gb.on_start # called once before the loop
230
+ @gb.on_update # called every frame — game logic
231
+ @gb.on_draw # called every frame — raw pygame drawing
232
+ @gb.on_stop # called once on exit
233
+ ```
234
+
235
+ ---
236
+
237
+ ## Requirements
238
+
239
+ - Python ≥ 3.9
240
+ - pygame-ce ≥ 2.5
241
+ - pytmx ≥ 3.31 *(optional, for TMX loading)*
242
+ - Pillow ≥ 9.0 *(optional, for PNG tileset loading)*
243
+
244
+ ---
245
+
246
+ ## License
247
+
248
+ MIT — see [LICENSE](LICENSE) for details.
@@ -0,0 +1,188 @@
1
+ # PyGB
2
+
3
+ A **Game Boy-style 2D game making library** for Python, built on [pygame-ce](https://pyga.me).
4
+
5
+ 160×144 viewport · 4-colour palette · GB-authentic audio channels · Tiled TMX map support · Collision editor
6
+
7
+ ---
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ pip install pygb
13
+ ```
14
+
15
+ **Optional extras:**
16
+
17
+ ```bash
18
+ pip install "pygb[tmx]" # Tiled .tmx map support (pytmx)
19
+ pip install "pygb[image]" # PNG tileset loading (Pillow)
20
+ pip install "pygb[all]" # Both of the above
21
+ ```
22
+
23
+ ---
24
+
25
+ ## Quick Start
26
+
27
+ ```python
28
+ from pygb import GameBoy, Tile
29
+ import pygb.color as color
30
+
31
+ gb = GameBoy(title="My Game", scale=3, palette=color.DMG)
32
+
33
+ player_tile = Tile([
34
+ [0, 0, 1, 1, 1, 1, 0, 0],
35
+ [0, 1, 3, 3, 3, 3, 1, 0],
36
+ [0, 1, 3, 2, 2, 3, 1, 0],
37
+ [0, 1, 3, 3, 3, 3, 1, 0],
38
+ [0, 0, 1, 1, 1, 1, 0, 0],
39
+ [0, 0, 1, 0, 0, 1, 0, 0],
40
+ [0, 0, 1, 0, 0, 1, 0, 0],
41
+ [0, 0, 0, 0, 0, 0, 0, 0],
42
+ ])
43
+ player = gb.create_sprite(player_tile, x=76, y=68)
44
+
45
+ @gb.on_update
46
+ def update():
47
+ dx, dy = gb.input.direction()
48
+ player.move(dx * 2, dy * 2)
49
+ player.clamp(0, 0, 152, 136)
50
+ if dx < 0: player.flip_x = True
51
+ elif dx > 0: player.flip_x = False
52
+
53
+ gb.run()
54
+ ```
55
+
56
+ ---
57
+
58
+ ## TMX Map Example
59
+
60
+ Load a full-colour Tiled map with camera and tile collision:
61
+
62
+ ```python
63
+ import os, json
64
+ from pygb import GameBoy, Tile, Camera, CollisionMap, load_tmx, clamp
65
+
66
+ gb = GameBoy(title="TMX Demo", scale=3)
67
+
68
+ @gb.on_start
69
+ def init():
70
+ global result, cmap, player, cam, px, py
71
+
72
+ result = load_tmx(gb, "level.tmx")
73
+ gb.graphics.bg_enabled = False # full-colour rendering via on_draw
74
+
75
+ cmap = CollisionMap(result.map_cols, result.map_rows, tile_size=result.tile_size)
76
+ if os.path.exists("level_collision.json"):
77
+ with open("level_collision.json") as f:
78
+ saved = json.load(f)
79
+ cmap.from_grid(saved["data"], solid_value=1)
80
+
81
+ px, py = float(result.world_w // 2), float(result.world_h // 2)
82
+ cam = Camera(gb.graphics,
83
+ world_w=result.world_w, world_h=result.world_h,
84
+ screen_w=gb.width, screen_h=gb.height)
85
+ cam.follow(px, py, smooth=1.0)
86
+
87
+ @gb.on_update
88
+ def update():
89
+ global px, py
90
+ dx, dy = gb.input.direction()
91
+ px, py = cmap.resolve(px, py, 8, 8, dx * 2, dy * 2)
92
+ px = clamp(px, 0, result.world_w - 8)
93
+ py = clamp(py, 0, result.world_h - 8)
94
+ cam.follow(px, py, smooth=0.15)
95
+
96
+ @gb.on_draw
97
+ def draw():
98
+ ts, sx, sy = result.tile_size, gb.graphics.scroll_x, gb.graphics.scroll_y
99
+ gb.surface.fill((0, 0, 0))
100
+ for name in result.layer_order:
101
+ tilemap = result.layers[name]
102
+ cols, rows = gb.width // ts + 2, gb.height // ts + 2
103
+ for ty in range(rows):
104
+ for tx in range(cols):
105
+ idx = tilemap.get((tx + sx // ts) % tilemap.WIDTH,
106
+ (ty + sy // ts) % tilemap.HEIGHT)
107
+ if idx in result.surfaces:
108
+ gb.surface.blit(result.surfaces[idx],
109
+ (tx * ts - sx % ts, ty * ts - sy % ts))
110
+
111
+ gb.run()
112
+ ```
113
+
114
+ ---
115
+
116
+ ## Collision Editor
117
+
118
+ Paint solid/passable tiles on a PNG tileset or a Tiled `.tmx` map and save as JSON:
119
+
120
+ ```bash
121
+ # PNG tileset
122
+ pygb-editor tileset.png
123
+ pygb-editor tileset.png output.json
124
+
125
+ # Tiled TMX map (all layers rendered automatically)
126
+ pygb-editor level.tmx
127
+ pygb-editor level.tmx level_collision.json
128
+
129
+ # Advanced editor with startup dialog
130
+ pygb-collision
131
+ pygb-collision tileset.png
132
+ pygb-collision --blank 20x18 blank_collision.json
133
+ ```
134
+
135
+ | Key | Action |
136
+ |-----|--------|
137
+ | Left click / drag | Mark tiles solid |
138
+ | Right click / drag | Mark tiles passable |
139
+ | Middle drag | Pan |
140
+ | Scroll | Zoom in / out |
141
+ | `S` | Save JSON |
142
+ | `Z` | Undo |
143
+ | `R` | Clear all |
144
+ | `Escape` | Quit |
145
+
146
+ ---
147
+
148
+ ## Features
149
+
150
+ | Feature | Details |
151
+ |---------|---------|
152
+ | Viewport | 160×144 px (configurable) |
153
+ | Tile size | Any size (default 8×8, auto-detected) |
154
+ | VRAM | 256 tiles max |
155
+ | Sprites | Position, flip, palette, AABB collision |
156
+ | Tilemaps | BG (scrollable) + Window (HUD overlay) |
157
+ | Palettes | DMG · GRAY · POCKET · GBC |
158
+ | Audio | 2× Pulse · Wave · Noise (GB-style) |
159
+ | TMX loader | Full-colour rendering via pytmx |
160
+ | Collision | Tile-resolution AABB with wall sliding |
161
+ | Font | Built-in 8×8 bitmap font |
162
+ | Utilities | Camera · Timer · Animation · RNG · Rect |
163
+
164
+ ---
165
+
166
+ ## Lifecycle Hooks
167
+
168
+ ```python
169
+ @gb.on_start # called once before the loop
170
+ @gb.on_update # called every frame — game logic
171
+ @gb.on_draw # called every frame — raw pygame drawing
172
+ @gb.on_stop # called once on exit
173
+ ```
174
+
175
+ ---
176
+
177
+ ## Requirements
178
+
179
+ - Python ≥ 3.9
180
+ - pygame-ce ≥ 2.5
181
+ - pytmx ≥ 3.31 *(optional, for TMX loading)*
182
+ - Pillow ≥ 9.0 *(optional, for PNG tileset loading)*
183
+
184
+ ---
185
+
186
+ ## License
187
+
188
+ MIT — see [LICENSE](LICENSE) for details.
@@ -0,0 +1,248 @@
1
+ Metadata-Version: 2.4
2
+ Name: pygame-gb
3
+ Version: 0.1.0
4
+ Summary: A Game Boy-style 2D game making library for Python
5
+ Author-email: Chawanwit Akarajirathanachot <chawanwit.akarajirathanachot@gmail.com>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2026 Chawanwit Akarajirathanachot
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Project-URL: Homepage, https://github.com/Karibura-Cyber/PyGB
29
+ Project-URL: Documentation, https://github.com/Karibura-Cyber/PyGB#readme
30
+ Project-URL: Bug Tracker, https://github.com/Karibura-Cyber/PyGB/issues
31
+ Project-URL: Source, https://github.com/Karibura-Cyber/PyGB
32
+ Keywords: gameboy,game-boy,retro,pixel,pygame,2d,game-engine,tilemap,tiled,sprite
33
+ Classifier: Development Status :: 3 - Alpha
34
+ Classifier: Intended Audience :: Developers
35
+ Classifier: Intended Audience :: Education
36
+ Classifier: License :: OSI Approved :: MIT License
37
+ Classifier: Operating System :: OS Independent
38
+ Classifier: Programming Language :: Python :: 3
39
+ Classifier: Programming Language :: Python :: 3.9
40
+ Classifier: Programming Language :: Python :: 3.10
41
+ Classifier: Programming Language :: Python :: 3.11
42
+ Classifier: Programming Language :: Python :: 3.12
43
+ Classifier: Programming Language :: Python :: 3.13
44
+ Classifier: Programming Language :: Python :: 3.14
45
+ Classifier: Topic :: Games/Entertainment
46
+ Classifier: Topic :: Multimedia :: Graphics
47
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
48
+ Requires-Python: >=3.9
49
+ Description-Content-Type: text/markdown
50
+ License-File: LICENSE
51
+ Requires-Dist: pygame-ce>=2.5
52
+ Provides-Extra: tmx
53
+ Requires-Dist: pytmx>=3.31; extra == "tmx"
54
+ Provides-Extra: image
55
+ Requires-Dist: Pillow>=9.0; extra == "image"
56
+ Provides-Extra: all
57
+ Requires-Dist: pytmx>=3.31; extra == "all"
58
+ Requires-Dist: Pillow>=9.0; extra == "all"
59
+ Dynamic: license-file
60
+
61
+ # PyGB
62
+
63
+ A **Game Boy-style 2D game making library** for Python, built on [pygame-ce](https://pyga.me).
64
+
65
+ 160×144 viewport · 4-colour palette · GB-authentic audio channels · Tiled TMX map support · Collision editor
66
+
67
+ ---
68
+
69
+ ## Install
70
+
71
+ ```bash
72
+ pip install pygb
73
+ ```
74
+
75
+ **Optional extras:**
76
+
77
+ ```bash
78
+ pip install "pygb[tmx]" # Tiled .tmx map support (pytmx)
79
+ pip install "pygb[image]" # PNG tileset loading (Pillow)
80
+ pip install "pygb[all]" # Both of the above
81
+ ```
82
+
83
+ ---
84
+
85
+ ## Quick Start
86
+
87
+ ```python
88
+ from pygb import GameBoy, Tile
89
+ import pygb.color as color
90
+
91
+ gb = GameBoy(title="My Game", scale=3, palette=color.DMG)
92
+
93
+ player_tile = Tile([
94
+ [0, 0, 1, 1, 1, 1, 0, 0],
95
+ [0, 1, 3, 3, 3, 3, 1, 0],
96
+ [0, 1, 3, 2, 2, 3, 1, 0],
97
+ [0, 1, 3, 3, 3, 3, 1, 0],
98
+ [0, 0, 1, 1, 1, 1, 0, 0],
99
+ [0, 0, 1, 0, 0, 1, 0, 0],
100
+ [0, 0, 1, 0, 0, 1, 0, 0],
101
+ [0, 0, 0, 0, 0, 0, 0, 0],
102
+ ])
103
+ player = gb.create_sprite(player_tile, x=76, y=68)
104
+
105
+ @gb.on_update
106
+ def update():
107
+ dx, dy = gb.input.direction()
108
+ player.move(dx * 2, dy * 2)
109
+ player.clamp(0, 0, 152, 136)
110
+ if dx < 0: player.flip_x = True
111
+ elif dx > 0: player.flip_x = False
112
+
113
+ gb.run()
114
+ ```
115
+
116
+ ---
117
+
118
+ ## TMX Map Example
119
+
120
+ Load a full-colour Tiled map with camera and tile collision:
121
+
122
+ ```python
123
+ import os, json
124
+ from pygb import GameBoy, Tile, Camera, CollisionMap, load_tmx, clamp
125
+
126
+ gb = GameBoy(title="TMX Demo", scale=3)
127
+
128
+ @gb.on_start
129
+ def init():
130
+ global result, cmap, player, cam, px, py
131
+
132
+ result = load_tmx(gb, "level.tmx")
133
+ gb.graphics.bg_enabled = False # full-colour rendering via on_draw
134
+
135
+ cmap = CollisionMap(result.map_cols, result.map_rows, tile_size=result.tile_size)
136
+ if os.path.exists("level_collision.json"):
137
+ with open("level_collision.json") as f:
138
+ saved = json.load(f)
139
+ cmap.from_grid(saved["data"], solid_value=1)
140
+
141
+ px, py = float(result.world_w // 2), float(result.world_h // 2)
142
+ cam = Camera(gb.graphics,
143
+ world_w=result.world_w, world_h=result.world_h,
144
+ screen_w=gb.width, screen_h=gb.height)
145
+ cam.follow(px, py, smooth=1.0)
146
+
147
+ @gb.on_update
148
+ def update():
149
+ global px, py
150
+ dx, dy = gb.input.direction()
151
+ px, py = cmap.resolve(px, py, 8, 8, dx * 2, dy * 2)
152
+ px = clamp(px, 0, result.world_w - 8)
153
+ py = clamp(py, 0, result.world_h - 8)
154
+ cam.follow(px, py, smooth=0.15)
155
+
156
+ @gb.on_draw
157
+ def draw():
158
+ ts, sx, sy = result.tile_size, gb.graphics.scroll_x, gb.graphics.scroll_y
159
+ gb.surface.fill((0, 0, 0))
160
+ for name in result.layer_order:
161
+ tilemap = result.layers[name]
162
+ cols, rows = gb.width // ts + 2, gb.height // ts + 2
163
+ for ty in range(rows):
164
+ for tx in range(cols):
165
+ idx = tilemap.get((tx + sx // ts) % tilemap.WIDTH,
166
+ (ty + sy // ts) % tilemap.HEIGHT)
167
+ if idx in result.surfaces:
168
+ gb.surface.blit(result.surfaces[idx],
169
+ (tx * ts - sx % ts, ty * ts - sy % ts))
170
+
171
+ gb.run()
172
+ ```
173
+
174
+ ---
175
+
176
+ ## Collision Editor
177
+
178
+ Paint solid/passable tiles on a PNG tileset or a Tiled `.tmx` map and save as JSON:
179
+
180
+ ```bash
181
+ # PNG tileset
182
+ pygb-editor tileset.png
183
+ pygb-editor tileset.png output.json
184
+
185
+ # Tiled TMX map (all layers rendered automatically)
186
+ pygb-editor level.tmx
187
+ pygb-editor level.tmx level_collision.json
188
+
189
+ # Advanced editor with startup dialog
190
+ pygb-collision
191
+ pygb-collision tileset.png
192
+ pygb-collision --blank 20x18 blank_collision.json
193
+ ```
194
+
195
+ | Key | Action |
196
+ |-----|--------|
197
+ | Left click / drag | Mark tiles solid |
198
+ | Right click / drag | Mark tiles passable |
199
+ | Middle drag | Pan |
200
+ | Scroll | Zoom in / out |
201
+ | `S` | Save JSON |
202
+ | `Z` | Undo |
203
+ | `R` | Clear all |
204
+ | `Escape` | Quit |
205
+
206
+ ---
207
+
208
+ ## Features
209
+
210
+ | Feature | Details |
211
+ |---------|---------|
212
+ | Viewport | 160×144 px (configurable) |
213
+ | Tile size | Any size (default 8×8, auto-detected) |
214
+ | VRAM | 256 tiles max |
215
+ | Sprites | Position, flip, palette, AABB collision |
216
+ | Tilemaps | BG (scrollable) + Window (HUD overlay) |
217
+ | Palettes | DMG · GRAY · POCKET · GBC |
218
+ | Audio | 2× Pulse · Wave · Noise (GB-style) |
219
+ | TMX loader | Full-colour rendering via pytmx |
220
+ | Collision | Tile-resolution AABB with wall sliding |
221
+ | Font | Built-in 8×8 bitmap font |
222
+ | Utilities | Camera · Timer · Animation · RNG · Rect |
223
+
224
+ ---
225
+
226
+ ## Lifecycle Hooks
227
+
228
+ ```python
229
+ @gb.on_start # called once before the loop
230
+ @gb.on_update # called every frame — game logic
231
+ @gb.on_draw # called every frame — raw pygame drawing
232
+ @gb.on_stop # called once on exit
233
+ ```
234
+
235
+ ---
236
+
237
+ ## Requirements
238
+
239
+ - Python ≥ 3.9
240
+ - pygame-ce ≥ 2.5
241
+ - pytmx ≥ 3.31 *(optional, for TMX loading)*
242
+ - Pillow ≥ 9.0 *(optional, for PNG tileset loading)*
243
+
244
+ ---
245
+
246
+ ## License
247
+
248
+ MIT — see [LICENSE](LICENSE) for details.