Skip to content

Commit d6dc963

Browse files
committed
map_editor: JSON save/load (canonical map-format v1)
Replaces the legacy map.bin binary format (PUTBYTE/GETBYTE per cell) with a v1 map.json the runtime's MAPLOAD statement consumes unchanged. Save writes the canonical schema via OPEN+PRINT#: format/id/size/tileSize/tilesets[walls.png]/layers[bg].data. Load calls MAPLOAD, then copies MAP_BG into the editor's local MAP() array. Probes the file with OPEN+ST=1 first so a missing path shows a friendly status instead of a runtime error. Editor remains a 10x10 grid; saved files round-trip through MAPLOAD identically (verified via shooter / rpg fixtures already in this repo). The .bin path is dropped — no migration tool, since map.bin files were per-user scratch state.
1 parent e3d9a6f commit d6dc963

1 file changed

Lines changed: 82 additions & 20 deletions

File tree

examples/map_editor.bas

Lines changed: 82 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,19 @@
33
'
44
' Demonstrates SCREEN 4 (640x400 RGBA) for a desktop-style UI:
55
' toolbar buttons, tile picker, map grid, mouse paint, plus
6-
' binary file SAVE / LOAD of the edited map.
6+
' JSON file SAVE / LOAD against the canonical map format
7+
' (docs/map-format.md v1).
78
'
89
' Tile graphics come from walls.png grid of
910
' 32x32 cells -> TILEMAP DRAW; 0 = blank).
1011
'
1112
' Render model: full-frame redraw. CLS each tick wipes both the
1213
' bitmap plane and the per-frame TILEMAP cell list (cap 4096),
1314
' so continuous paint can never overflow it.
15+
'
16+
' Save format: writes a v1 map.json file via PRINT# — a 10x10
17+
' bg tile layer, no objects, no camera. Load uses the runtime's
18+
' MAPLOAD statement, which validates schema and fills MAP_BG().
1419
' ============================================================
1520

1621
SCREEN 4
@@ -43,7 +48,23 @@ BTN_QUIT_X0 = 592 : BTN_QUIT_Y0 = 4 : BTN_QUIT_X1 = 632 : BTN_QUIT_Y1 = 24
4348

4449
DIM PICKER(PICK_COUNT)
4550
DIM MAP(MAP_COUNT)
51+
' MAPLOAD targets — pre-DIMmed at MAP_COUNT so a JSON read fills
52+
' MAP_BG and we copy back into MAP(). Other MAP_* arrays exist so
53+
' MAPLOAD's writes don't crash on missing globals.
54+
DIM MAP_BG(MAP_COUNT - 1)
55+
DIM MAP_FG(MAP_COUNT - 1)
56+
DIM MAP_COLL(15)
57+
DIM MAP_OBJ_TYPE$(15)
58+
DIM MAP_OBJ_KIND$(15)
59+
DIM MAP_OBJ_X(15)
60+
DIM MAP_OBJ_Y(15)
61+
DIM MAP_OBJ_W(15)
62+
DIM MAP_OBJ_H(15)
63+
DIM MAP_OBJ_ID(15)
64+
DIM MAP_TILESET_ID$(7)
65+
DIM MAP_TILESET_SRC$(7)
4666
SELECTED = 1
67+
Q$ = CHR$(34)
4768

4869
' Status line state — re-stamped every frame after CLS.
4970
STATUS$ = "LEFT CLICK A TILE, THEN LEFT CLICK + DRAG ON THE MAP. RIGHT CLICK CLEARS."
@@ -78,29 +99,13 @@ DO
7899
IF MX >= BTN_QUIT_X0 AND MX <= BTN_QUIT_X1 AND MY >= BTN_QUIT_Y0 AND MY <= BTN_QUIT_Y1 THEN EXIT
79100

80101
IF MX >= BTN_SAVE_X0 AND MX <= BTN_SAVE_X1 AND MY >= BTN_SAVE_Y0 AND MY <= BTN_SAVE_Y1 THEN
81-
OPEN 1, 1, 1, "map.bin"
82-
FOR I = 0 TO MAP_COUNT - 1
83-
PUTBYTE #1, MAP(I)
84-
NEXT I
85-
CLOSE #1
86-
STATUS$ = "SAVED map.bin"
102+
SaveMapJson()
103+
STATUS$ = "SAVED map.json"
87104
STATUS_R = 200 : STATUS_G = 255 : STATUS_B = 200
88105
END IF
89106

90107
IF MX >= BTN_LOAD_X0 AND MX <= BTN_LOAD_X1 AND MY >= BTN_LOAD_Y0 AND MY <= BTN_LOAD_Y1 THEN
91-
OPEN 1, 1, 0, "map.bin"
92-
IF ST = 1 THEN
93-
STATUS$ = "NO map.bin YET - SAVE FIRST"
94-
STATUS_R = 255 : STATUS_G = 200 : STATUS_B = 200
95-
ELSE
96-
FOR I = 0 TO MAP_COUNT - 1
97-
GETBYTE #1, B
98-
IF B >= 0 AND B <= PICK_COUNT THEN MAP(I) = B ELSE MAP(I) = 0
99-
NEXT I
100-
CLOSE #1
101-
STATUS$ = "LOADED map.bin"
102-
STATUS_R = 200 : STATUS_G = 200 : STATUS_B = 255
103-
END IF
108+
LoadMapJson()
104109
END IF
105110

106111
IF MX >= PICKER_X AND MX < PICKER_X + PCOLS * TILE_SIZE AND MY >= PICKER_Y AND MY < PICKER_Y + PROWS * TILE_SIZE THEN
@@ -207,3 +212,60 @@ FUNCTION DrawStatus()
207212
COLORRGB STATUS_R, STATUS_G, STATUS_B
208213
DRAWTEXT 8, 384, STATUS$
209214
END FUNCTION
215+
216+
' ------------------------------------------------------------
217+
' JSON save / load — canonical map format v1
218+
' ------------------------------------------------------------
219+
220+
FUNCTION SaveMapJson()
221+
' Writes a v1 map.json: format/size/tileSize/tilesets/layers[bg].
222+
' No object layer, no camera — this editor only paints a tile grid.
223+
OPEN 1, 1, 1, "map.json"
224+
PRINT#1, "{"
225+
PRINT#1, " " + Q$ + "format" + Q$ + ": 1,"
226+
PRINT#1, " " + Q$ + "id" + Q$ + ": " + Q$ + "editor-map" + Q$ + ","
227+
PRINT#1, " " + Q$ + "size" + Q$ + ": { " + Q$ + "cols" + Q$ + ": " + STR$(MCOLS) + ", " + Q$ + "rows" + Q$ + ": " + STR$(MROWS) + " },"
228+
PRINT#1, " " + Q$ + "tileSize" + Q$ + ": { " + Q$ + "w" + Q$ + ": 32, " + Q$ + "h" + Q$ + ": 32 },"
229+
PRINT#1, " " + Q$ + "tilesets" + Q$ + ": ["
230+
PRINT#1, " { " + Q$ + "id" + Q$ + ": " + Q$ + "walls" + Q$ + ", " + Q$ + "src" + Q$ + ": " + Q$ + "walls.png" + Q$ + ", " + Q$ + "cellW" + Q$ + ": 32, " + Q$ + "cellH" + Q$ + ": 32 }"
231+
PRINT#1, " ],"
232+
PRINT#1, " " + Q$ + "layers" + Q$ + ": ["
233+
PRINT#1, " { " + Q$ + "name" + Q$ + ": " + Q$ + "bg" + Q$ + ", " + Q$ + "type" + Q$ + ": " + Q$ + "tiles" + Q$ + ", " + Q$ + "tilesetId" + Q$ + ": " + Q$ + "walls" + Q$ + ","
234+
PRINT#1, " " + Q$ + "data" + Q$ + ": ["
235+
FOR SI = 0 TO MAP_COUNT - 1
236+
IF SI < MAP_COUNT - 1 THEN
237+
PRINT#1, " " + STR$(MAP(SI)) + ","
238+
ELSE
239+
PRINT#1, " " + STR$(MAP(SI))
240+
END IF
241+
NEXT SI
242+
PRINT#1, " ]"
243+
PRINT#1, " }"
244+
PRINT#1, " ]"
245+
PRINT#1, "}"
246+
CLOSE #1
247+
END FUNCTION
248+
249+
FUNCTION LoadMapJson()
250+
' Probe for the file first — MAPLOAD raises a runtime error on a
251+
' missing path, which would kill the editor. ST=1 after OPEN signals
252+
' "not found"; bail out with a friendly status instead.
253+
OPEN 1, 1, 0, "map.json"
254+
IF ST = 1 THEN
255+
STATUS$ = "NO map.json YET - SAVE FIRST"
256+
STATUS_R = 255 : STATUS_G = 200 : STATUS_B = 200
257+
RETURN 0
258+
END IF
259+
CLOSE #1
260+
MAPLOAD "map.json"
261+
IF MAP_W = MCOLS AND MAP_H = MROWS THEN
262+
FOR LI = 0 TO MAP_COUNT - 1
263+
MAP(LI) = MAP_BG(LI)
264+
NEXT LI
265+
STATUS$ = "LOADED map.json"
266+
STATUS_R = 200 : STATUS_G = 200 : STATUS_B = 255
267+
ELSE
268+
STATUS$ = "MAP SIZE MISMATCH - EXPECTED " + STR$(MCOLS) + "x" + STR$(MROWS)
269+
STATUS_R = 255 : STATUS_G = 200 : STATUS_B = 200
270+
END IF
271+
END FUNCTION

0 commit comments

Comments
 (0)