Use when creating a new map or track for Junk Runner — designing the layout, drawing in Tiled, running the TMX conversion pipeline, and wiring the generated C files into the game.
Step-by-step guide to create a new map from scratch. Uses the Tiled → tmx_to_c.py → GB pipeline.
REQUIRED BACKGROUND: Use the map-expert agent (Agent tool) before writing any code — it has the full pipeline reference, GID rules, and GBDK API details.
png_to_tiles.pystart objectgroup with one spawn objecttmx_to_c.py → verify generated C#includeIf extending the existing tileset (assets/maps/tileset.aseprite):
make export-sprites or aseprite --batch assets/maps/tileset.aseprite --save-as assets/maps/tileset.pngpython3 tools/png_to_tiles.py --bank <N> assets/maps/tileset.png src/track_tiles.c track_tile_dataIf creating a new tileset for a new map:
.aseprite under assets/maps/<mapname>_tiles.asepriteassets/maps/<mapname>_tiles.pngpython3 tools/png_to_tiles.py --bank <N> assets/maps/<mapname>_tiles.png src/<mapname>_tiles.c <mapname>_tile_dataTile budget: 192 tiles in DMG bank 0, 192 more in CGB bank 1. Keep total unique tiles ≤ 192 for DMG compat.
.tsx (or create one from the PNG)tmx_to_c.py)assets/maps/<name>.tmx with CSV encoding (File → Map Properties → Tile Layer Format: CSV)Map constraints:
start with exactly one objectpython3 tools/tmx_to_c.py assets/maps/<name>.tmx src/<name>_map.c
Outputs src/<name>_map.c with:
track_start_x, track_start_y — spawn pixel coordstrack_map[] — tile index array, row-majorRun the conversion tests to verify the tool still works:
python3 -m unittest discover -s tests -p "test_tmx_to_c.py" -v
Never edit src/<name>_map.c by hand — it is generated. Edit the TMX and re-run.
In the relevant .h / .c for your map system:
/* Declare generated symbols (in your map .h) */
extern const uint8_t track_map[];
extern const int16_t track_start_x;
extern const int16_t track_start_y;
extern const uint8_t track_tile_data[];
extern const uint8_t track_tile_data_count;
Loading sequence (must happen during / immediately after VBlank):
wait_vbl_done();
set_bkg_data(0, track_tile_data_count, track_tile_data); /* load tile graphics */
set_bkg_tiles(0, 0, MAP_TILES_W, MAP_TILES_H, track_map); /* write tilemap */
SHOW_BKG;
Map dimensions must be declared in src/config.h:
#define MAP_TILES_W 40
#define MAP_TILES_H 36
Update these if your new map has different dimensions.
Generated files from tmx_to_c.py already include #pragma bank 255 and BANKREF. When loading:
{ SET_BANK(track_map);
set_bkg_tiles(0, 0, MAP_TILES_W, MAP_TILES_H, track_map);
RESTORE_BANK(); }
Wrap tile data load similarly if track_tile_data is in a banked file.
GBDK_HOME=/home/mathdaman/gbdk make
java -jar /home/mathdaman/.local/share/emulicious/Emulicious.jar build/nuke-raider.gb
Check:
| Mistake | Fix |
|---|---|
Editing generated src/*_map.c by hand | Always edit the TMX and re-run tmx_to_c.py |
| Map layer not named "Track" | tmx_to_c.py looks for this layer name exactly |
Missing start objectgroup | Script requires exactly one objectgroup named start |
| VRAM writes after game logic | Always call wait_vbl_done() → tile data → tilemap → then game logic |
| Tile count > 192 | DMG VRAM limit; use CGB bank 1 for overflow or reduce tiles |
| Using base64 encoding in Tiled | Set Tile Layer Format to CSV before saving |
map-expert agent — Full pipeline reference, GID math, GBDK BG API, CGB attribute mapsprite-expert agent — For OAM sprites on top of the mapgbdk-expert agent — VBlank rules, LCDC register, set_bkg_data details