summaryrefslogtreecommitdiff
path: root/tilemap.lua
diff options
context:
space:
mode:
Diffstat (limited to 'tilemap.lua')
-rw-r--r--tilemap.lua192
1 files changed, 192 insertions, 0 deletions
diff --git a/tilemap.lua b/tilemap.lua
new file mode 100644
index 0000000..64ca520
--- /dev/null
+++ b/tilemap.lua
@@ -0,0 +1,192 @@
+local Entity = require("entity")
+
+local Tilemap = {}
+Tilemap.__index = Tilemap
+
+local function loadMapData(mapPath)
+ if type(mapPath) ~= "string" then
+ return mapPath
+ end
+ if love and love.filesystem and love.filesystem.load then
+ local chunk, err = love.filesystem.load(mapPath)
+ if not chunk then
+ error("Tilemap: failed to load '" .. tostring(mapPath) .. "': " .. tostring(err))
+ end
+ return chunk()
+ end
+ local mod = mapPath:gsub("%.lua$", ""):gsub("/", ".")
+ local ok, data = pcall(require, mod)
+ if not ok then
+ error("Tilemap: failed to load '" .. tostring(mapPath) .. "': " .. tostring(data))
+ end
+ return data
+end
+
+local function objectToEntity(obj)
+ local x = obj.x or 0
+ local y = obj.y or 0
+ local w = obj.width or 0
+ local h = obj.height or 0
+ local entity = Entity:new(x, y, w, h)
+ entity:setPropertiesFromOptions({
+ properties = obj.properties or {},
+ name = obj.name,
+ type = obj.type,
+ id = obj.id,
+ rotation = obj.rotation,
+ visible = obj.visible
+ })
+ return entity
+end
+
+function Tilemap:new(map)
+ local self = setmetatable({}, Tilemap)
+
+ self.entitiesTiles = {}
+ self.entitiesSpawns = {}
+ self.entitiesCameraBorders = {}
+ self.layerBackground = nil
+ self.layerGround = nil
+ self.layerForeground = nil
+ self.tileWidth = 16
+ self.tileHeight = 16
+ self.mapWidth = 0
+ self.mapHeight = 0
+ self.tilesetImage = nil
+ self.tileQuads = {}
+
+ local mapData = loadMapData(map)
+ self.mapData = mapData
+
+ self.tileWidth = mapData and (mapData.tilewidth or 16) or 16
+ self.tileHeight = mapData and (mapData.tileheight or 16) or 16
+ self.mapWidth = (mapData and mapData.width or 0) * self.tileWidth
+ self.mapHeight = (mapData and mapData.height or 0) * self.tileHeight
+
+ if type(map) == "string" then
+ local basePath = map:gsub("%.lua$", ""):gsub("%.tmx$", "")
+ local imagePath = basePath .. ".png"
+ local ok, img = pcall(love.graphics.newImage, imagePath)
+ if ok and img then
+ self.tilesetImage = img
+ local firstGid = (mapData.tilesets and mapData.tilesets[1] and mapData.tilesets[1].firstgid) or 1
+ local imgW, imgH = img:getDimensions()
+ local tw, th = self.tileWidth, self.tileHeight
+ local cols = math.floor(imgW / tw)
+ local rows = math.floor(imgH / th)
+ for index = 0, (cols * rows) - 1 do
+ local qx = (index % cols) * tw
+ local qy = math.floor(index / cols) * th
+ self.tileQuads[firstGid + index] = love.graphics.newQuad(qx, qy, tw, th, imgW, imgH)
+ end
+ end
+ end
+
+ if mapData and mapData.layers then
+ for _, layer in ipairs(mapData.layers) do
+ if layer.type == "tilelayer" and layer.name then
+ local n = layer.name:lower()
+ if n == "background" then self.layerBackground = layer
+ elseif n == "ground" then self.layerGround = layer
+ elseif n == "foreground" then self.layerForeground = layer
+ end
+ elseif layer.type == "objectgroup" and layer.objects then
+ local name = (layer.name or ""):gsub("%s+", "_"):lower()
+ for _, obj in ipairs(layer.objects) do
+ local entity = objectToEntity(obj)
+ if name == "tiles" or name == "tile" then
+ table.insert(self.entitiesTiles, entity)
+ elseif name == "spawn" then
+ table.insert(self.entitiesSpawns, entity)
+ elseif name == "camera_border" then
+ table.insert(self.entitiesCameraBorders, entity)
+ end
+ end
+ end
+ end
+ end
+
+ return self
+end
+
+function Tilemap:getEntitiesTiles()
+ return self.entitiesTiles
+end
+
+function Tilemap:getEntitiesSpawns()
+ return self.entitiesSpawns
+end
+
+function Tilemap:getEntitiesCameraBorders()
+ return self.entitiesCameraBorders
+end
+
+-- Returns minX, maxX, minY, maxY from camera_border entities for use with Camera:setLimits.
+-- Returns nil, nil, nil, nil if there are no camera border entities.
+function Tilemap:getCameraLimits()
+ local borders = self.entitiesCameraBorders
+ if not borders or #borders == 0 then
+ return nil, nil, nil, nil
+ end
+ local minX, maxX = math.huge, -math.huge
+ local minY, maxY = math.huge, -math.huge
+ for _, e in ipairs(borders) do
+ local x, y = e.x or 0, e.y or 0
+ local w, h = e.width or 0, e.height or 0
+ minX = math.min(minX, x)
+ maxX = math.max(maxX, x + w)
+ minY = math.min(minY, y)
+ maxY = math.max(maxY, y + h)
+ end
+ return minX, maxX, minY, maxY
+end
+
+function Tilemap:getMapData()
+ return self.mapData
+end
+
+function Tilemap:getBackgroundLayer()
+ return self.layerBackground
+end
+
+function Tilemap:getGroundLayer()
+ return self.layerGround
+end
+
+function Tilemap:getForegroundLayer()
+ return self.layerForeground
+end
+
+function Tilemap:getLayers()
+ return {
+ background = self.layerBackground,
+ ground = self.layerGround,
+ foreground = self.layerForeground
+ }
+end
+
+function Tilemap:getTileWidth()
+ return self.tileWidth
+end
+
+function Tilemap:getTileHeight()
+ return self.tileHeight
+end
+
+function Tilemap:getMapWidth()
+ return self.mapWidth
+end
+
+function Tilemap:getMapHeight()
+ return self.mapHeight
+end
+
+function Tilemap:getTilesetImage()
+ return self.tilesetImage
+end
+
+function Tilemap:getTileQuads()
+ return self.tileQuads
+end
+
+return Tilemap