-- Tilemap entity, it dynamically rebuilds its draw cache thingy -- You just need to worry not and use the tile getting/setting functions TILESIZE = 16 function new_tilemap(width, height) local map = new_entity() add_comp(map, "Tilemap", width, height) return map end function AUTO_ID(tl, tr, bl, br) return tl + 2 * tr + 4 * bl + 8 * br end local AUTOTILE_TBL = { ["0001"] = { 0, 0 }, ["0010"] = { 1, 0 }, ["0101"] = { 2, 0 }, ["1010"] = { 3, 0 }, ["0100"] = { 0, 1 }, ["1000"] = { 1, 1 }, ["0011"] = { 2, 1 }, ["1100"] = { 3, 1 }, ["1110"] = { 0, 2 }, ["1101"] = { 1, 2 }, ["0110"] = { 2, 2 }, ["1001"] = { 3, 2 }, ["1011"] = { 0, 3 }, ["0111"] = { 1, 3 }, ["1111"] = { 2, 3 }, ["0000"] = {} } local function ID(map, x, y) return x + y * map.width + 1 end -- local function POS(map, id) -- id = id - 1 -- return id % map.width, math.floor(id / map.width) -- end register_comp("Tilemap", function(tilemap, width, height) tilemap.tiledata = {} for i = 1, width * height do tilemap.tiledata[i] = 0 end tilemap.width = width tilemap.height = height tilemap.cache = {} tilemap.cachesize = 0 tilemap.needs_rebuild = false end) function AUTOTILE_CODE(map, x, y) local typ local tl = get_tile(map, x, y) if tl ~= 0 then typ = tl tl = 1 end local tr = get_tile(map, x + 1, y) if tr ~= 0 then typ = tr tr = 1 end local bl = get_tile(map, x, y + 1) if bl ~= 0 then typ = bl bl = 1 end local br = get_tile(map, x + 1, y + 1) if br ~= 0 then typ = br br = 1 end return tl .. tr .. bl .. br, typ end function rebuild_tilemap(map) map.cache = {} map.cachesize = 0 for x = -1, map.width do for y = -1, map.height do local code, typ = AUTOTILE_CODE(map, x, y) local tex_x, tex_y = unpack(AUTOTILE_TBL[code]) if typ then -- Adjust for tile type fr tex_y = tex_y + (typ - 1) * 4 map.cachesize = map.cachesize + 1 map.cache[map.cachesize] = { x = x * TILESIZE + TILESIZE/2, y = y * TILESIZE + TILESIZE/2, tex_x = tex_x * TILESIZE, tex_y = tex_y * TILESIZE, } end end end end TILE_TEX = get_tex("res/img/tilesets.png") local TILE_QUAD = lg.newQuad( 0, 0, TILESIZE, TILESIZE, TILE_TEX:getWidth(), TILE_TEX:getHeight()) function tilemap_draw_sys(tilemap) if tilemap.needs_rebuild then rebuild_tilemap(tilemap) tilemap.needs_rebuild = false end for i = 1, tilemap.cachesize do local tile = tilemap.cache[i] TILE_QUAD:setViewport(tile.tex_x, tile.tex_y, TILESIZE, TILESIZE) lg.draw(TILE_TEX, TILE_QUAD, tile.x, tile.y) end end function get_tile(map, x, y) if x < 0 or x >= map.width or y < 0 or y >= map.height then return 0 end return map.tiledata[ID(map, x, y)] end function has_tile(map, x, y) if x < 0 or x >= map.width or y < 0 or y >= map.height then return false end return map.tiledata[ID(map, x, y)] ~= 0 end function queue_tilemap_rebuild(tilemap) tilemap.needs_rebuild = true end function set_tile(map, x, y, tileid) map.tiledata[ID(map, x, y)] = tileid map.needs_rebuild = true end function to_tile_coords(x, y) return math.floor(x / TILESIZE), math.floor(y / TILESIZE) end function remove_tile(map, x, y) map.tiledata[ID(map, x, y)] = 0 map.needs_rebuild = true end function get_tileset_quad(tileset) local start_y = (tileset - 1) * 4 * TILESIZE return lg.newQuad( 0, start_y, 4 * TILESIZE, 4 * TILESIZE, TILE_TEX:getDimensions() ) end function get_tileset_count() return TILE_TEX:getHeight() / (4 * TILESIZE) end