From 2b5acb5caf13e2cc3d620af755868d65f2b441cc Mon Sep 17 00:00:00 2001 From: Axel Meyer Date: Mon, 18 May 2026 03:21:52 +0200 Subject: [PATCH] feat: v0.1.2 sprite-mode in draw_map + tile_rotations + load_textures Sprite-mode in draw_map: - tilemap-tiles with texture atlas-id render via engine.render.draw_sprite_transform with rotation pivot at tile center - tiles without texture continue to render via draw_rect with color (Phase 1 mode preserved) Tile rotation: - maps support an optional tile_rotations parallel array in the map JSON with per-cell 90-degree rotation values (0/90/180/270) - absent or nil entries default to 0 (no rotation) - enables 9-segment tile reuse via rotation rather than per-orientation sprites New API: - maps.load_textures(asset_aliases) resolves the current tilemap's tile atlas-ids to texture-handles via the asset-lib indirection (asset_aliases[tilemap.asset_pack] -> lib-id -> atlas.json lookup per tile) Schema additions: - tilemap.asset_pack (alias-key, optional) - tile.texture (atlas-id, optional) - map.tile_rotations (parallel array, optional) All existing Phase 1 color-only tilemaps render unchanged. --- README.md | 33 +++++++++++++++- init.lua | 109 +++++++++++++++++++++++++++++++++++++++++++++------ manifest.lib | 2 +- 3 files changed, 129 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 52f0b6b..0d81ea8 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Single tile-grid map implementation. Loads JSON map + tilemap files, registers maps by id, and provides tile-fetch + walkability + size queries with current-map sugar. -**Version:** 0.1.1 +**Version:** 0.1.2 **Lib-ID:** lib-core.maps **Requires:** (none) **Tags:** maps, tile-grid, walkability, tilemap @@ -93,6 +93,22 @@ if tile then engine.print(tile.id) end **Description:** Returns an array of all registered map-ids. +### `maps.load_textures(asset_aliases)` +**Syntax:** `maps.load_textures(asset_aliases: {[string]: string}) -> void` + +**Example:** +```lua +maps.set_current(map_id) +maps.load_textures({ terrain = "lib-core.terrain-assets" }) +``` + +**Description:** Resolves the current tilemap's tile `texture` atlas-ids to texture-handles via the asset-lib indirection. `asset_aliases` maps the tilemap's `asset_pack` alias-key to a lib-id; the lib's `assets/atlas.json` is read to locate each texture file. Populates `tile.texture_handle` on each tile in-place. No-op if the tilemap has no `asset_pack`. Call once at module init after `set_current`; do not call repeatedly (texture handles are not auto-cached). + +### `maps.draw_map()` +**Syntax:** `maps.draw_map() -> void` + +**Description:** Draws the current map grid. Tiles with a resolved `texture_handle` render via `engine.render.draw_sprite_transform` with rotation about the tile center (using the map's optional `tile_rotations` parallel array). Tiles without a texture handle fall back to `engine.render.draw_rect` with `tile.color` (Phase 1 mode). No-op if no current map. + ### `maps.state(map_id)` **Syntax:** `maps.state(map_id: string) -> string` @@ -130,6 +146,21 @@ end ## CHANGELOG +### v0.1.2 +- Sprite-mode in draw_map: tilemap-tiles with `texture` atlas-id render + via engine.render.draw_sprite_transform; tiles without `texture` fall + back to color-rect render (Phase 1 mode). +- Map-data tile_rotations parallel array support: per-cell 90-degree + rotation in {0, 90, 180, 270}, applied at draw via rotation about + the tile center. Optional; absent means all-zero. +- New API: maps.load_textures(asset_aliases) resolves the current + tilemap's tile atlas-ids to texture-handles via the asset-lib + indirection. Mirrors the puppet.load_textures pattern. +- Tilemap schema additions: tilemap.asset_pack (alias-key), + tile.texture (atlas-id). +- Backward-compat: existing Phase 1 color-only tilemaps render + unchanged. + ### v0.1.1 - Tilemap-id resolution handles module-ids with dots (prefix-match instead of first-dot split). diff --git a/init.lua b/init.lua index 666a28d..2d3ec3a 100644 --- a/init.lua +++ b/init.lua @@ -96,10 +96,22 @@ local function load_tilemap(full_id) local path = "assets/tiles/" .. local_name .. ".tilemap.json" local raw = engine.asset.load_json(path) validate_tilemap_table(raw, path, local_name) + -- Cook tiles: copy raw fields and add texture + texture_handle slots. + local cooked = {} + for i, t in ipairs(raw.tiles) do + cooked[i] = { + id = t.id, + walkable = (t.walkable == true), + color = t.color, -- color-mode fallback + texture = t.texture, -- optional atlas-id + texture_handle = nil, -- populated by load_textures + } + end local tilemap = { - id = full_id, - tile_size = raw.tile_size, - tiles = raw.tiles, + id = full_id, + tile_size = raw.tile_size, + asset_pack = raw.asset_pack, -- optional alias-key + tiles = cooked, } tilemap_registry[full_id] = tilemap return tilemap @@ -114,17 +126,18 @@ local function build_map(t_map, tilemap) end end return { - id = t_map.id, - size = t_map.size, - tile_size = t_map.tile_size or tilemap.tile_size, - tiles = t_map.tiles, -- shallow-ref - tilemap = tilemap, -- shallow-ref + id = t_map.id, + size = t_map.size, + tile_size = t_map.tile_size or tilemap.tile_size, + tiles = t_map.tiles, -- shallow-ref + tile_rotations = t_map.tile_rotations, -- optional parallel array (NEW) + tilemap = tilemap, -- shallow-ref -- DEPRECATED-MVP: forward-compat stubs (multi-map slice fills) - walls = {}, - regions = {}, - edges = {}, - state = "Active", - pinned = false, + walls = {}, + regions = {}, + edges = {}, + state = "Active", + pinned = false, } end @@ -227,6 +240,76 @@ function M.list() return out end +-- ==================================================================== +-- Resolve tilemap-tile atlas-ids to texture-handles via asset-lib. +-- Operates on the current map's tilemap; call after maps.set_current. +-- asset_aliases: { [alias-key] = asset-lib-id } from module's manifest. +-- ==================================================================== +function M.load_textures(asset_aliases) + local map_id = M.current() + if map_id == nil then + error("maps.load_textures: no current map; call maps.set_current first") + end + local m = map_registry[map_id] + local tm = m.tilemap + if tm.asset_pack == nil then return end -- color-only tilemap, no textures + local lib_id = asset_aliases[tm.asset_pack] + if lib_id == nil then + error("maps.load_textures: asset-pack alias '" .. tm.asset_pack + .. "' not in asset_aliases") + end + local atlas_path = lib_id .. "/assets/atlas.json" + local atlas = engine.asset.load_json(atlas_path) + local pack = atlas[tm.asset_pack] + if pack == nil then + error("maps.load_textures: asset_pack '" .. tm.asset_pack + .. "' not declared in atlas of '" .. lib_id .. "'") + end + for _, tile in ipairs(tm.tiles) do + if tile.texture then + local entry = pack[tile.texture] + if entry == nil then + error("maps.load_textures: atlas-id '" .. tile.texture + .. "' not in asset_pack '" .. tm.asset_pack .. "'") + end + tile.texture_handle = engine.asset.load_texture(lib_id .. "/assets/" .. entry.file) + end + end +end + +function M.draw_map() + local map_id = M.current() + if map_id == nil then return end + local m = map_registry[map_id] + local tm = m.tilemap + local ts = tm.tile_size + for y = 0, m.size.h - 1 do + for x = 0, m.size.w - 1 do + local idx = y * m.size.w + x + 1 + local tile_id = m.tiles[idx] + local tile = tm.tiles[tile_id] + local rot_deg = (m.tile_rotations and m.tile_rotations[idx]) or 0 + local px = x * ts + local py = y * ts + if tile.texture_handle then + -- Sprite mode: draw_sprite_transform with rotation about tile center. + engine.render.draw_sprite_transform( + tile.texture_handle, + px + ts / 2, py + ts / 2, + math.rad(rot_deg), + 1.0, 1.0, + ts / 2, ts / 2, + 0xFFFFFFFF + ) + else + -- Color fallback (Phase 1 mode). + local c = tile.color or { 100, 100, 100 } + engine.render.draw_rect(px, py, ts, ts, engine.render.rgb(c[1], c[2], c[3])) + end + end + end +end + -- Forward-compat stubs (DEPRECATED-MVP — implemented in later slices) function M.state(map_id) -- DEPRECATED-MVP: lifecycle states (Virgin/Inert/Passive/Active/Pinned) — multi-map slice diff --git a/manifest.lib b/manifest.lib index 70d1862..2ce11e8 100644 --- a/manifest.lib +++ b/manifest.lib @@ -1 +1 @@ -{"id":"lib-core.maps","version":"0.1.1","api_min":"0.1"} +{"id":"lib-core.maps","version":"0.1.2","api_min":"0.1"}