diff options
| -rw-r--r-- | entity.lua | 2 | ||||
| -rw-r--r-- | main.lua | 33 | ||||
| -rw-r--r-- | tilemap.lua | 72 | ||||
| -rw-r--r-- | world.lua | 36 |
4 files changed, 94 insertions, 49 deletions
@@ -34,7 +34,7 @@ end function Entity:syncFromPhysicsBody() if not self.body then return end - self.x = self.body:getX() - self.physicsWidth / 2 + self.x = self.body:getX() - self.physicsWidth self.y = self.body:getY() - self.height + self.physicsHeight / 2 end @@ -12,6 +12,7 @@ local offsetX, offsetY = 0, 0 local dpiScale = 1 local canvas = nil local smoothCameraShader = nil +local shaderEnabled = true local cameraModule = require("camera") local camera = nil @@ -19,7 +20,10 @@ local fonts = require("fonts") local currentState = "game" local currentMapPath = "assets/maps/tilemap.lua" -local currentTilesetPath = "assets/maps/tileset.png" +local currentTilesets = { + tileset = { path = "assets/maps/tileset.png", tilewidth = 16, tileheight = 16 }, + ground = { path = "assets/maps/ground.png", tilewidth = 8, tileheight = 8 }, +} local world = nil local states = { @@ -39,7 +43,7 @@ end function states.game.load() local World = require("world") world = World:new() - world:load(currentMapPath, currentTilesetPath) + world:load(currentMapPath, currentTilesets) local target = world:getPlayer() or { x = 0, y = 0, width = 16, height = 16 } camera = cameraModule:new(target, VIRTUAL_WIDTH/2, VIRTUAL_HEIGHT/2, true, WORLD_TO_CANVAS) world:setCamera(camera) @@ -116,6 +120,9 @@ function love.keypressed(key, scancode, isrepeat) if key == "f11" then love.window.setFullscreen(not love.window.getFullscreen(), "desktop") end + if key == "f1" and DEBUG then + shaderEnabled = not shaderEnabled + end if (key == "space" or key == "up" or key == "w") and not isrepeat then local player = world and world:getPlayer() if player then player:jump() end @@ -143,16 +150,34 @@ function love.draw() local uvOffsetX = subDx * WORLD_TO_CANVAS / CANVAS_WIDTH local uvOffsetY = subDy * WORLD_TO_CANVAS / CANVAS_HEIGHT - if smoothCameraShader and (subDx ~= 0 or subDy ~= 0) then + if shaderEnabled and smoothCameraShader and (subDx ~= 0 or subDy ~= 0) then smoothCameraShader:send("offset", { uvOffsetX, uvOffsetY }) love.graphics.setShader(smoothCameraShader) end love.graphics.draw(canvas, math.floor(drawX), math.floor(drawY), 0, finalScale, finalScale) - if smoothCameraShader then + if shaderEnabled and smoothCameraShader then love.graphics.setShader() end + + if DEBUG then + local fps = love.timer.getFPS() + local shaderLoaded = smoothCameraShader ~= nil + local shaderApplied = shaderEnabled and shaderLoaded and (subDx ~= 0 or subDy ~= 0) + local shaderName = shaderLoaded and "smooth_camera.glsl" or "none (fallback)" + local shaderState = not shaderLoaded and "unavailable" + or not shaderEnabled and "disabled [F1]" + or shaderApplied and "active" + or "idle" + local shaderLine = "shader: " .. shaderName .. " (" .. shaderState .. ")" + love.graphics.setColor(0, 0, 0, 0.5) + love.graphics.rectangle("fill", 4, 4, 280, 36) + love.graphics.setColor(1, 1, 0, 1) + love.graphics.print("FPS: " .. fps, 8, 8) + love.graphics.print(shaderLine, 8, 22) + love.graphics.setColor(1, 1, 1, 1) + end end return nil diff --git a/tilemap.lua b/tilemap.lua index 4780cfe..ab2a52c 100644 --- a/tilemap.lua +++ b/tilemap.lua @@ -39,7 +39,7 @@ local function objectToEntity(obj) return entity end -function Tilemap:new(mapPath, tilesetPath) +function Tilemap:new(mapPath, tilesets) local self = setmetatable({}, Tilemap) self.entitiesTiles = {} @@ -48,34 +48,40 @@ function Tilemap:new(mapPath, tilesetPath) self.layerBackground = nil self.layerGround = nil self.layerForeground = nil - self.tileWidth = 16 - self.tileHeight = 16 + self.tileWidth = 8 + self.tileHeight = 8 self.mapWidth = 0 self.mapHeight = 0 - self.tilesetImage = nil - self.tileQuads = {} + self.tileGidInfo = {} + self.layerTileDimensions = {} local mapData = loadMapData(mapPath) self.mapData = mapData - self.tileWidth = mapData and (mapData.tilewidth or 16) or 16 - self.tileHeight = mapData and (mapData.tileheight or 16) or 16 + self.tileWidth = mapData and (mapData.tilewidth or 8) or 8 + self.tileHeight = mapData and (mapData.tileheight or 8) or 8 self.mapWidth = (mapData and mapData.width or 0) * self.tileWidth self.mapHeight = (mapData and mapData.height or 0) * self.tileHeight - if type(tilesetPath) == "string" and tilesetPath ~= "" then - local ok, img = pcall(love.graphics.newImage, tilesetPath) - 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) + if mapData and mapData.tilesets then + for _, ts in ipairs(mapData.tilesets) do + local info = tilesets[ts.name] + if info then + local ok, img = pcall(love.graphics.newImage, info.path) + if ok and img then + local tw = info.tilewidth or self.tileWidth + local th = info.tileheight or self.tileHeight + local imgW, imgH = img:getDimensions() + 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 + local gid = ts.firstgid + index + local quad = love.graphics.newQuad(qx, qy, tw, th, imgW, imgH) + self.tileGidInfo[gid] = { image = img, quad = quad, tilewidth = tw, tileheight = th } + end + end end end end @@ -88,6 +94,19 @@ function Tilemap:new(mapPath, tilesetPath) elseif n == "ground" then self.layerGround = layer elseif n == "foreground" then self.layerForeground = layer end + local dims = nil + if layer.data then + for _, gid in ipairs(layer.data) do + if gid and gid ~= 0 then + local gi = self.tileGidInfo[gid] + if gi then + dims = { tilewidth = gi.tilewidth, tileheight = gi.tileheight } + break + end + end + end + end + self.layerTileDimensions[n] = dims or { tilewidth = self.tileWidth, tileheight = self.tileHeight } elseif layer.type == "objectgroup" and layer.objects then local name = (layer.name or ""):gsub("%s+", "_"):lower() for _, obj in ipairs(layer.objects) do @@ -169,6 +188,11 @@ function Tilemap:getTileHeight() return self.tileHeight end +function Tilemap:getLayerTileDimensions(layerName) + return self.layerTileDimensions[layerName:lower()] + or { tilewidth = self.tileWidth, tileheight = self.tileHeight } +end + function Tilemap:getMapWidth() return self.mapWidth end @@ -177,12 +201,8 @@ function Tilemap:getMapHeight() return self.mapHeight end -function Tilemap:getTilesetImage() - return self.tilesetImage -end - -function Tilemap:getTileQuads() - return self.tileQuads +function Tilemap:getTileGidInfo() + return self.tileGidInfo end return Tilemap @@ -26,7 +26,7 @@ function World:new() return self end -function World:load(mapPath, tilesetPath) +function World:load(mapPath, tilesets) if self.physicsWorld then self.groundEntities = {} end @@ -43,14 +43,15 @@ function World:load(mapPath, tilesetPath) end ) - self.tilemap = Tilemap:new(mapPath, tilesetPath) + self.tilemap = Tilemap:new(mapPath, tilesets) self.mapData = self.tilemap:getMapData() if not self.mapData then error("World:load - no map data from " .. tostring(mapPath)) end - local tileWidth = self.tilemap:getTileWidth() - local tileHeight = self.tilemap:getTileHeight() + local groundDims = self.tilemap:getLayerTileDimensions("ground") + local tileWidth = groundDims.tilewidth + local tileHeight = groundDims.tileheight local groundLayer = self.tilemap:getGroundLayer() if groundLayer and groundLayer.data then @@ -205,7 +206,7 @@ function World:getMapData() return self.mapData end -local function drawTileLayer(layer, tileWidth, tileHeight, tilesetImage, tileQuads) +local function drawTileLayer(layer, mapTileW, mapTileH, tileGidInfo) if not layer or not layer.visible or not layer.data then return end local w = layer.width or 0 local data = layer.data @@ -214,16 +215,17 @@ local function drawTileLayer(layer, tileWidth, tileHeight, tilesetImage, tileQua local idx = i - 1 local tx = idx % w local ty = math.floor(idx / w) - local x = tx * tileWidth - local y = ty * tileHeight - if tilesetImage and tileQuads and tileQuads[gid] then - love.graphics.draw(tilesetImage, tileQuads[gid], x, y) + local x = tx * mapTileW + local y = ty * mapTileH + local info = tileGidInfo and tileGidInfo[gid] + if info then + love.graphics.draw(info.image, info.quad, x, y) else local r = ((gid * 17) % 256) / 255 local g = ((gid * 31 + 50) % 256) / 255 local b = ((gid * 47 + 100) % 256) / 255 love.graphics.setColor(r, g, b, 1) - love.graphics.rectangle("fill", x, y, tileWidth, tileHeight) + love.graphics.rectangle("fill", x, y, mapTileW, mapTileH) love.graphics.setColor(1, 1, 1, 1) end end @@ -231,14 +233,12 @@ local function drawTileLayer(layer, tileWidth, tileHeight, tilesetImage, tileQua end function World:draw() - local tw = self.tilemap:getTileWidth() - local th = self.tilemap:getTileHeight() - local tilesetImage = self.tilemap:getTilesetImage() - local tileQuads = self.tilemap:getTileQuads() - - drawTileLayer(self.tilemap:getBackgroundLayer(), tw, th, tilesetImage, tileQuads) + local mapTileW = self.tilemap:getTileWidth() + local mapTileH = self.tilemap:getTileHeight() + local tileGidInfo = self.tilemap:getTileGidInfo() - drawTileLayer(self.tilemap:getGroundLayer(), tw, th, tilesetImage, tileQuads) + drawTileLayer(self.tilemap:getBackgroundLayer(), mapTileW, mapTileH, tileGidInfo) + drawTileLayer(self.tilemap:getGroundLayer(), mapTileW, mapTileH, tileGidInfo) for _, e in ipairs(self.entities) do if e.draw then e:draw() else World.drawEntityDefault(e) end @@ -249,7 +249,7 @@ function World:draw() World.drawPhysicsBodyOutlines(self.groundEntities) end - drawTileLayer(self.tilemap:getForegroundLayer(), tw, th, tilesetImage, tileQuads) + drawTileLayer(self.tilemap:getForegroundLayer(), mapTileW, mapTileH, tileGidInfo) end function World.drawPhysicsBodyOutlines(entityList) |
